From 620b176267a5d5684d85e2d90e98e29dd4808942 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Tue, 17 Mar 2015 10:04:34 -0700 Subject: INSTALL.md: Add a few notes for Windows builds. Signed-off-by: Ben Pfaff Acked-by: Gurucharan Shetty --- INSTALL.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/INSTALL.md b/INSTALL.md index 273093baf..b2b0cbb82 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -10,6 +10,7 @@ on a specific platform, please see one of these files: - [INSTALL.RHEL.md] - [INSTALL.XenServer.md] - [INSTALL.NetBSD.md] + - [INSTALL.Windows.md] - [INSTALL.DPDK.md] Build Requirements @@ -28,6 +29,9 @@ you will need the following software: analysis and thread-safety checks. For Ubuntu, there are nightly built packages available on clang's website. + * MSVC 2013. See [INSTALL.Windows] for additional Windows build + instructions. + While OVS may be compatible with other compilers, optimal support for atomic operations may be missing, making OVS very slow (see lib/ovs-atomic.h). -- cgit v1.2.1 From 86b3f7e1c805fa1a9f78b9df2772a1780402fbcb Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Tue, 17 Mar 2015 10:04:47 -0700 Subject: INSTALL.md: Note that Clang and ccache aren't completely compatible. CC: Russell Bryant Signed-off-by: Ben Pfaff Acked-by: Russell Bryant --- INSTALL.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/INSTALL.md b/INSTALL.md index b2b0cbb82..3762e0054 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -259,6 +259,10 @@ Building the Sources For improved warnings if you installed "sparse" (see "Prerequisites"), add C=1 to the command line. + Some versions of Clang and ccache are not completely compatible. + If you see unusual warnings when you use both together, consider + disabling ccache for use with Clang. + 2. Consider running the testsuite. Refer to "Running the Testsuite" below, for instructions. -- cgit v1.2.1 From c7952afb1258f4282140de52baa51ab59ae169e6 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Fri, 13 Mar 2015 11:30:18 -0700 Subject: netdev-linux: Be more careful about integer overflow in policing. Otherwise the policing limits could make no sense if large rates were specified. Reported-by: Zhangguanghui Signed-off-by: Ben Pfaff Acked-by: Ansis Atteka --- AUTHORS | 1 + lib/netdev-linux.c | 29 ++++++++++++++++++++++------- vswitchd/bridge.c | 4 ++-- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/AUTHORS b/AUTHORS index fe79acd28..d7925db4b 100644 --- a/AUTHORS +++ b/AUTHORS @@ -345,6 +345,7 @@ Voravit T. voravit@kth.se Yeming Zhao zhaoyeming@gmail.com Ying Chen yingchen@vmware.com Yongqiang Liu liuyq7809@gmail.com +Zhangguanghui zhang.guanghui@h3c.com Ziyou Wang ziyouw@vmware.com Zoltán Balogh zoltan.balogh@ericsson.com ankur dwivedi ankurengg2003@gmail.com diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index 662ccc975..6e574cdbc 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc. + * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -399,8 +399,8 @@ static struct tcmsg *tc_make_request(const struct netdev *, int type, unsigned int flags, struct ofpbuf *); static int tc_transact(struct ofpbuf *request, struct ofpbuf **replyp); static int tc_add_del_ingress_qdisc(struct netdev *netdev, bool add); -static int tc_add_policer(struct netdev *netdev, int kbits_rate, - int kbits_burst); +static int tc_add_policer(struct netdev *, + uint32_t kbits_rate, uint32_t kbits_burst); static int tc_parse_qdisc(const struct ofpbuf *, const char **kind, struct nlattr **options); @@ -4028,12 +4028,13 @@ tc_add_del_ingress_qdisc(struct netdev *netdev, bool add) * mtu 65535 drop * * The configuration and stats may be seen with the following command: - * /sbin/tc -s filter show eth0 parent ffff: + * /sbin/tc -s filter show dev parent ffff: * * Returns 0 if successful, otherwise a positive errno value. */ static int -tc_add_policer(struct netdev *netdev, int kbits_rate, int kbits_burst) +tc_add_policer(struct netdev *netdev, + uint32_t kbits_rate, uint32_t kbits_burst) { struct tc_police tc_police; struct ofpbuf request; @@ -4047,8 +4048,22 @@ tc_add_policer(struct netdev *netdev, int kbits_rate, int kbits_burst) tc_police.action = TC_POLICE_SHOT; tc_police.mtu = mtu; tc_fill_rate(&tc_police.rate, ((uint64_t) kbits_rate * 1000)/8, mtu); - tc_police.burst = tc_bytes_to_ticks(tc_police.rate.rate, - kbits_burst * 1024); + + /* The following appears wrong in two ways: + * + * - tc_bytes_to_ticks() should take "bytes" as quantity for both of its + * arguments (or at least consistently "bytes" as both or "bits" as + * both), but this supplies bytes for the first argument and bits for the + * second. + * + * - In networking a kilobit is usually 1000 bits but this uses 1024 bits. + * + * However if you "fix" those problems then "tc filter show ..." shows + * "125000b", meaning 125,000 bits, when OVS configures it for 1000 kbit == + * 1,000,000 bits, whereas this actually ends up doing the right thing from + * tc's point of view. Whatever. */ + tc_police.burst = tc_bytes_to_ticks( + tc_police.rate.rate, MIN(UINT32_MAX / 1024, kbits_burst) * 1024); tcmsg = tc_make_request(netdev, RTM_NEWTFILTER, NLM_F_EXCL | NLM_F_CREATE, &request); diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index 85bbfa3f2..68648b9bc 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -4445,8 +4445,8 @@ iface_configure_qos(struct iface *iface, const struct ovsrec_qos *qos) } netdev_set_policing(iface->netdev, - iface->cfg->ingress_policing_rate, - iface->cfg->ingress_policing_burst); + MIN(UINT32_MAX, iface->cfg->ingress_policing_rate), + MIN(UINT32_MAX, iface->cfg->ingress_policing_burst)); ofpbuf_uninit(&queues_buf); } -- cgit v1.2.1 From ed9c9e3e087ab8892229154c2098410eee17b554 Mon Sep 17 00:00:00 2001 From: Jarno Rajahalme Date: Wed, 11 Mar 2015 18:01:51 -0700 Subject: ofproto-dpif-xlate: Preserve and execute action_set on a patch port. Prevent a peer bridge from seeing or modifying the action_set of the first bridge. Also execute the accumulated action set on the peer bridge, if any. Found by inspection. Signed-off-by: Jarno Rajahalme Acked-by: Ben Pfaff --- ofproto/ofproto-dpif-xlate.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index 3691d728b..81a7f7221 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -223,12 +223,14 @@ struct xlate_ctx { * 'action_set' accumulates "struct ofpact"s added by OFPACT_WRITE_ACTIONS. * When translation is otherwise complete, ofpacts_execute_action_set() * converts it to a set of "struct ofpact"s that can be translated into - * datapath actions. */ + * datapath actions. */ bool action_set_has_group; /* Action set contains OFPACT_GROUP? */ struct ofpbuf action_set; /* Action set. */ uint64_t action_set_stub[1024 / 8]; }; +static void xlate_action_set(struct xlate_ctx *ctx); + /* A controller may use OFPP_NONE as the ingress port to indicate that * it did not arrive on a "real" port. 'ofpp_none_bundle' exists for * when an input bundle is needed for validation (e.g., mirroring or @@ -2733,8 +2735,11 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, uint8_t table_id = rule_dpif_lookup_get_init_table_id(&ctx->xin->flow); struct ofpbuf old_stack = ctx->stack; union mf_subvalue new_stack[1024 / sizeof(union mf_subvalue)]; + struct ofpbuf old_action_set = ctx->action_set; + uint64_t actset_stub[1024 / 8]; ofpbuf_use_stub(&ctx->stack, new_stack, sizeof new_stack); + ofpbuf_use_stub(&ctx->action_set, actset_stub, sizeof actset_stub); ctx->xbridge = peer->xbridge; flow->in_port.ofp_port = peer->ofp_port; flow->metadata = htonll(0); @@ -2750,6 +2755,10 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, if (xport_stp_forward_state(peer) && xport_rstp_forward_state(peer)) { xlate_table_action(ctx, flow->in_port.ofp_port, table_id, true, true); + if (ctx->action_set.size) { + /* Translate action set only if not dropping the packet. */ + xlate_action_set(ctx); + } } else { /* Forwarding is disabled by STP and RSTP. Let OFPP_NORMAL and * the learning action look at the packet, then drop it. */ @@ -2766,6 +2775,8 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, ctx->xin->flow = old_flow; ctx->xbridge = xport->xbridge; + ofpbuf_uninit(&ctx->action_set); + ctx->action_set = old_action_set; ofpbuf_uninit(&ctx->stack); ctx->stack = old_stack; @@ -3778,6 +3789,8 @@ xlate_action_set(struct xlate_ctx *ctx) ctx->in_action_set = true; ofpbuf_use_stub(&action_list, action_list_stub, sizeof action_list_stub); ofpacts_execute_action_set(&action_list, &ctx->action_set); + /* Clear the action set, as it is not needed any more. */ + ofpbuf_clear(&ctx->action_set); do_xlate_actions(action_list.data, action_list.size, ctx); ctx->in_action_set = false; ofpbuf_uninit(&action_list); -- cgit v1.2.1 From f3d5b47390c3c1db31444b8dd5d7f635438a805d Mon Sep 17 00:00:00 2001 From: Jarno Rajahalme Date: Thu, 12 Mar 2015 09:47:31 -0700 Subject: ofproto-dpif-xlate: Do not exit if peer bridge exits. The fact that the peer bridge exits (for any reason) does not mean that the original bridge should exit. Specifically, if the peer bridge recirculates (which typically modifies the packet), the original bridge must continue processing with the original, not the recirculated packet! Signed-off-by: Jarno Rajahalme Acked-by: Ben Pfaff --- ofproto/ofproto-dpif-xlate.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index 81a7f7221..0e28c777f 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -2765,6 +2765,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, struct flow old_base_flow = ctx->base_flow; size_t old_size = ctx->xout->odp_actions->size; mirror_mask_t old_mirrors = ctx->xout->mirrors; + xlate_table_action(ctx, flow->in_port.ofp_port, table_id, true, true); ctx->xout->mirrors = old_mirrors; @@ -2780,6 +2781,13 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, ofpbuf_uninit(&ctx->stack); ctx->stack = old_stack; + /* The fact that the peer bridge exits (for any reason) does not mean + * that the original bridge should exit. Specifically, if the peer + * bridge recirculates (which typically modifies the packet), the + * original bridge must continue processing with the original, not the + * recirculated packet! */ + ctx->exit = false; + if (ctx->xin->resubmit_stats) { netdev_vport_inc_tx(xport->netdev, ctx->xin->resubmit_stats); netdev_vport_inc_rx(peer->netdev, ctx->xin->resubmit_stats); -- cgit v1.2.1 From 0792d095fbc93a253fefd56c8e1d625cfed16c1c Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Mon, 9 Mar 2015 10:10:56 +0900 Subject: Use NTR rather than NTR as prefix for Netronome vendor id As pointed out by Ben Pfaff NTR (NetronoMe eXtension) is confusingly similar to NXM (Nicira eXtended Match?) which is already used widely in the Open vSwitch tree. To get ease future eye strain use NTR (NeTRonome) instead of NTR, starting with the only instance currently present in the tree, the Netronome vendor id. This is in preparation for actually using the Netronome vendor id. Signed-off-by: Simon Horman Signed-off-by: Ben Pfaff --- include/openflow/openflow-common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/openflow/openflow-common.h b/include/openflow/openflow-common.h index e68ab1424..e4fecceef 100644 --- a/include/openflow/openflow-common.h +++ b/include/openflow/openflow-common.h @@ -103,7 +103,7 @@ enum ofp_version { */ #define OF_VENDOR_ID 0 #define HPL_VENDOR_ID 0x000004EA /* HP Labs. */ -#define NMX_VENDOR_ID 0x00001540 /* Netronome. */ +#define NTR_VENDOR_ID 0x00001540 /* Netronome. */ #define NX_VENDOR_ID 0x00002320 /* Nicira. */ #define ONF_VENDOR_ID 0x4f4e4600 /* Open Networking Foundation. */ -- cgit v1.2.1 From 71d6ab4533bd3320acaee738d65ccd98a5ecdb78 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Tue, 17 Mar 2015 14:39:27 -0700 Subject: include/openflow: Simplify structure checking for OpenFlow headers. This means that anyone who adds another openflow include file automatically gets it checked. It does mean that changing any of the OpenFlow headers causes all of them to be checked, but that doesn't seem like a big deal (it's quick). Signed-off-by: Ben Pfaff Acked-by: Thomas Graf --- include/openflow/automake.mk | 36 ++---------------------------------- 1 file changed, 2 insertions(+), 34 deletions(-) diff --git a/include/openflow/automake.mk b/include/openflow/automake.mk index 512991e57..50933d5be 100644 --- a/include/openflow/automake.mk +++ b/include/openflow/automake.mk @@ -17,42 +17,10 @@ SUFFIXES += .h .hstamp $(AM_V_GEN)$(run_python) $(srcdir)/build-aux/check-structs -I$(srcdir)/include $< && \ touch $@ -HSTAMP_FILES = \ - include/openflow/nicira-ext.hstamp \ - include/openflow/openflow-1.0.hstamp \ - include/openflow/openflow-1.1.hstamp \ - include/openflow/openflow-1.2.hstamp \ - include/openflow/openflow-1.3.hstamp \ - include/openflow/openflow-1.4.hstamp \ - include/openflow/openflow-1.5.hstamp \ - include/openflow/openflow-common.hstamp \ - include/openflow/openflow.hstamp +HSTAMP_FILES = $(openflowinclude_HEADERS:.h=.hstamp) CLEANFILES += $(HSTAMP_FILES) ALL_LOCAL += $(HSTAMP_FILES) -$(HSTAMP_FILES): build-aux/check-structs - -include/openflow/openflow-1.0.hstamp: \ - include/openflow/openflow-common.h -include/openflow/openflow-1.1.hstamp: \ - include/openflow/openflow-common.h -include/openflow/openflow-1.2.hstamp: \ - include/openflow/openflow-common.h \ - include/openflow/openflow-1.1.h -include/openflow/openflow-1.3.hstamp: \ - include/openflow/openflow-common.h \ - include/openflow/openflow-1.1.h \ - include/openflow/openflow-1.2.h -include/openflow/openflow-1.4.hstamp: \ - include/openflow/openflow-1.4.h -include/openflow/openflow-1.5.hstamp: \ - include/openflow/openflow-1.5.h -include/openflow/nicira-ext.hstamp: \ - include/openflow/openflow.h \ - include/openflow/openflow-common.h \ - include/openflow/openflow-1.0.h \ - include/openflow/openflow-1.1.h \ - include/openflow/openflow-1.2.h \ - include/openflow/openflow-1.3.h +$(HSTAMP_FILES): build-aux/check-structs $(openflowinclude_HEADERS) endif EXTRA_DIST += build-aux/check-structs -- cgit v1.2.1 From 38b01df60dc8688f934bfe13e9d28cb43f3a5829 Mon Sep 17 00:00:00 2001 From: Gurucharan Shetty Date: Tue, 17 Mar 2015 15:23:22 -0700 Subject: INSTALL.Windows.md: Mention the easy way to get into bash. Just typing 'bash' from MSVC developers command prompt _can_ cause MSYS to use the Windows version of 'sort' instead of the GNU sort. Reported-by: Hemanth Kumar Mantri Signed-off-by: Gurucharan Shetty Acked-by: Eitan Eliahu --- AUTHORS | 1 + INSTALL.Windows.md | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/AUTHORS b/AUTHORS index d7925db4b..008f6f184 100644 --- a/AUTHORS +++ b/AUTHORS @@ -246,6 +246,7 @@ Gur Stavi gstavi@mrv.com Hari Sasank Bhamidipalli hbhamidi@cisco.com Hassan Khan hassan.khan@seecs.edu.pk Hector Oron hector.oron@gmail.com +Hemanth Kumar Mantri mantri@nutanix.com Henrik Amren henrik@nicira.com Hiroshi Tanaka htanaka@nicira.com Hiroshi Miyata miyahiro.dazu@gmail.com diff --git a/INSTALL.Windows.md b/INSTALL.Windows.md index 258e2fb79..e84013aab 100644 --- a/INSTALL.Windows.md +++ b/INSTALL.Windows.md @@ -35,11 +35,13 @@ install Windows Driver Kit (WDK) 8.1 Update. It is important to get the Visual Studio related environment variables and to have the $PATH inside the bash to point to the proper compiler and linker. One easy way to achieve this is to get into the "Developer Command prompt for visual -studio" and through it enter into the bash shell available from msys. +studio" and through it enter into the bash shell available from msys by typing +'bash --login'. If after the above step, a 'which link' inside MSYS's bash says, "/bin/link.exe", rename /bin/link.exe to something else so that the -Visual studio's linker is used. +Visual studio's linker is used. You should also see a 'which sort' report +"/bin/sort.exe". * For pthread support, install the library, dll and includes of pthreads-win32 project from -- cgit v1.2.1 From ac3e3aaa0a9be3f5fed6b9b65509efd6b377778a Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Fri, 13 Mar 2015 14:46:23 -0700 Subject: netdev-linux: Avoid RTM_GETQDISC bug workaround on new-enough kernels. Otherwise we can't detect classless qdiscs. This has no useful effect for the currently supported qdiscs, which all have classes, but it makes it possible to add support for new classless qdiscs. This suddenly makes netdev-linux complain about qdiscs it doesn't know about (e.g. pfifo_fast), which isn't too useful, so this commit also demotes that INFO message to DBG level. Reported-by: Jonathan Vestin Signed-off-by: Ben Pfaff --- AUTHORS | 1 + lib/netdev-linux.c | 49 +++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/AUTHORS b/AUTHORS index 008f6f184..db4520f37 100644 --- a/AUTHORS +++ b/AUTHORS @@ -268,6 +268,7 @@ Joan Cirer joan@ev0.net John Darrington john@darrington.wattle.id.au John Galgay john@galgay.net John Hurley john.hurley@netronome.com +Jonathan Vestin jonavest@kau.se K 華 k940545@hotmail.com Kevin Mancuso kevin.mancuso@rackspace.com Kiran Shanbhog kiran@vmware.com diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index 6e574cdbc..9b2e74f7e 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -4405,6 +4406,31 @@ tc_del_qdisc(struct netdev *netdev_) return error; } +static bool +getqdisc_is_safe(void) +{ + static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER; + static bool safe = false; + + if (ovsthread_once_start(&once)) { + struct utsname utsname; + int major, minor; + + if (uname(&utsname) == -1) { + VLOG_WARN("uname failed (%s)", ovs_strerror(errno)); + } else if (!ovs_scan(utsname.release, "%d.%d", &major, &minor)) { + VLOG_WARN("uname reported bad OS release (%s)", utsname.release); + } else if (major < 2 || (major == 2 && minor < 35)) { + VLOG_INFO("disabling unsafe RTM_GETQDISC in Linux kernel %s", + utsname.release); + } else { + safe = true; + } + ovsthread_once_done(&once); + } + return safe; +} + /* If 'netdev''s qdisc type and parameters are not yet known, queries the * kernel to determine what they are. Returns 0 if successful, otherwise a * positive errno value. */ @@ -4434,18 +4460,21 @@ tc_query_qdisc(const struct netdev *netdev_) * create will have a class with handle 1:0. The built-in qdiscs only have * a class with handle 0:0. * - * We could check for Linux 2.6.35+ and use a more straightforward method - * there. */ + * On Linux 2.6.35+ we use the straightforward method because it allows us + * to handle non-builtin qdiscs without handle 1:0 (e.g. codel). However, + * in such a case we get no response at all from the kernel (!) if a + * builtin qdisc is in use (which is later caught by "!error && + * !qdisc->size"). */ tcmsg = tc_make_request(netdev_, RTM_GETQDISC, NLM_F_ECHO, &request); if (!tcmsg) { return ENODEV; } - tcmsg->tcm_handle = tc_make_handle(1, 0); - tcmsg->tcm_parent = 0; + tcmsg->tcm_handle = tc_make_handle(getqdisc_is_safe() ? 0 : 1, 0); + tcmsg->tcm_parent = getqdisc_is_safe() ? TC_H_ROOT : 0; /* Figure out what tc class to instantiate. */ error = tc_transact(&request, &qdisc); - if (!error) { + if (!error && qdisc->size) { const char *kind; error = tc_parse_qdisc(qdisc, &kind, NULL); @@ -4455,15 +4484,15 @@ tc_query_qdisc(const struct netdev *netdev_) ops = tc_lookup_linux_name(kind); if (!ops) { static struct vlog_rate_limit rl2 = VLOG_RATE_LIMIT_INIT(1, 1); - VLOG_INFO_RL(&rl2, "unknown qdisc \"%s\"", kind); + VLOG_DBG_RL(&rl2, "unknown qdisc \"%s\"", kind); ops = &tc_ops_other; } } - } else if (error == ENOENT) { - /* Either it's a built-in qdisc, or it's a qdisc set up by some - * other entity that doesn't have a handle 1:0. We will assume - * that it's the system default qdisc. */ + } else if ((!error && !qdisc->size) || error == ENOENT) { + /* Either it's a built-in qdisc, or (on Linux pre-2.6.35) it's a qdisc + * set up by some other entity that doesn't have a handle 1:0. We will + * assume that it's the system default qdisc. */ ops = &tc_ops_default; error = 0; } else { -- cgit v1.2.1 From b6b0e049fd51e1d434ca2ecbbb98c11d4f805f76 Mon Sep 17 00:00:00 2001 From: Alex Wang Date: Wed, 18 Mar 2015 10:44:27 -0700 Subject: ovs-appctl-bashcomp: Use better function to complete file. This commit uses the _filedir function defined in bash_completion module for file completion. It will take care of the '/' suffix for directory. Signed-off-by: Alex Wang --- utilities/ovs-appctl-bashcomp.bash | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/utilities/ovs-appctl-bashcomp.bash b/utilities/ovs-appctl-bashcomp.bash index 0d83549ad..67a268eda 100755 --- a/utilities/ovs-appctl-bashcomp.bash +++ b/utilities/ovs-appctl-bashcomp.bash @@ -589,8 +589,9 @@ _ovs_command_complete() { COMPREPLY=( $(compgen -W "$(echo $_COMP_WORDLIST | tr ' ' '\n' \ | sort -u | sed -e '/NO_EXPAN/d')" -- $cur) ) else + compopt -o nospace # If there is no completions, just complete on file path. - COMPREPLY=( $(compgen -o filenames -A file -- $cur) ) + _filedir fi fi -- cgit v1.2.1 From 58be9c9fd732b5bdd3d4c2e9b8cc2313f570094d Mon Sep 17 00:00:00 2001 From: "Mark D. Gray" Date: Wed, 18 Mar 2015 17:09:06 +0000 Subject: automake.mk: Improve schema checksum error message. Signed-off-by: Mark D. Gray Signed-off-by: Billy O'Mahony Signed-off-by: Ben Pfaff --- vswitchd/automake.mk | 2 +- vtep/automake.mk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/vswitchd/automake.mk b/vswitchd/automake.mk index 2f07c0fc7..81f201a45 100644 --- a/vswitchd/automake.mk +++ b/vswitchd/automake.mk @@ -63,7 +63,7 @@ vswitchd/vswitch.ovsschema.stamp: vswitchd/vswitch.ovsschema touch $@; \ else \ ln=`sed -n '/"cksum":/=' $?`; \ - echo >&2 "$?:$$ln: checksum \"$$sum\" does not match (you should probably update the version number and fix the checksum)"; \ + echo >&2 "$?:$$ln: The checksum \"$$sum\" was calculated from the schema file and does not match cksum field in the schema file - you should probably update the version number and the checksum in the schema file with the value listed here."; \ exit 1; \ fi CLEANFILES += vswitchd/vswitch.ovsschema.stamp diff --git a/vtep/automake.mk b/vtep/automake.mk index 184d85f61..c712b0c91 100644 --- a/vtep/automake.mk +++ b/vtep/automake.mk @@ -87,7 +87,7 @@ vtep/vtep.ovsschema.stamp: vtep/vtep.ovsschema touch $@; \ else \ ln=`sed -n '/"cksum":/=' $?`; \ - echo >&2 "$?:$$ln: checksum \"$$sum\" does not match (you should probably update the version number and fix the checksum)"; \ + echo >&2 "$?:$$ln: The checksum \"$$sum\" was calculated from the schema file and does not match cksum field in the schema file - you should probably update the version number and the checksum in the schema file with the value listed here."; \ exit 1; \ fi CLEANFILES += vtep/vtep.ovsschema.stamp -- cgit v1.2.1 From 58397e6c1e6c0b68a0f3f32ded463df8087021d8 Mon Sep 17 00:00:00 2001 From: Kevin Traynor Date: Thu, 5 Mar 2015 13:42:04 -0800 Subject: netdev-dpdk: add dpdk vhost-cuse ports This patch adds support for a new port type to userspace datapath called dpdkvhost. This allows KVM (QEMU) to offload the servicing of virtio-net devices to its associated dpdkvhost port. Instructions for use are in INSTALL.DPDK. This has been tested on Intel multi-core platforms and with clients that have virtio-net interfaces. Signed-off-by: Ciara Loftus Signed-off-by: Kevin Traynor Signed-off-by: Maryam Tahhan Signed-off-by: Pravin B Shelar --- INSTALL.DPDK.md | 254 +++++++++++++++++++++++- Makefile.am | 4 + NEWS | 1 + acinclude.m4 | 4 +- lib/netdev-dpdk.c | 511 +++++++++++++++++++++++++++++++++++++++++++----- lib/netdev.c | 3 +- utilities/automake.mk | 3 +- utilities/qemu-wrap.py | 389 ++++++++++++++++++++++++++++++++++++ vswitchd/ovs-vswitchd.c | 10 +- 9 files changed, 1123 insertions(+), 56 deletions(-) create mode 100755 utilities/qemu-wrap.py diff --git a/INSTALL.DPDK.md b/INSTALL.DPDK.md index 276fe562e..a3e2a1db8 100644 --- a/INSTALL.DPDK.md +++ b/INSTALL.DPDK.md @@ -17,6 +17,7 @@ Building and Installing: ------------------------ Required DPDK 1.8.0 +Optional `fuse`, `fuse-devel` 1. Configure build & install DPDK: 1. Set `$DPDK_DIR` @@ -290,12 +291,262 @@ A general rule of thumb for better performance is that the client application should not be assigned the same dpdk core mask "-c" as the vswitchd. +DPDK vhost: +----------- + +vhost-cuse is only supported at present i.e. not using the standard QEMU +vhost-user interface. It is intended that vhost-user support will be added +in future releases when supported in DPDK and that vhost-cuse will eventually +be deprecated. See [DPDK Docs] for more info on vhost. + +Prerequisites: +1. DPDK 1.8 with vhost support enabled and recompile OVS as above. + + Update `config/common_linuxapp` so that DPDK is built with vhost + libraries: + + `CONFIG_RTE_LIBRTE_VHOST=y` + +2. Insert the Cuse module: + + `modprobe cuse` + +3. Build and insert the `eventfd_link` module: + + `cd $DPDK_DIR/lib/librte_vhost/eventfd_link/` + `make` + `insmod $DPDK_DIR/lib/librte_vhost/eventfd_link.ko` + +Following the steps above to create a bridge, you can now add DPDK vhost +as a port to the vswitch. + +`ovs-vsctl add-port br0 dpdkvhost0 -- set Interface dpdkvhost0 type=dpdkvhost` + +Unlike DPDK ring ports, DPDK vhost ports can have arbitrary names: + +`ovs-vsctl add-port br0 port123ABC -- set Interface port123ABC type=dpdkvhost` + +However, please note that when attaching userspace devices to QEMU, the +name provided during the add-port operation must match the ifname parameter +on the QEMU command line. + + +DPDK vhost VM configuration: +---------------------------- + + vhost ports use a Linux* character device to communicate with QEMU. + By default it is set to `/dev/vhost-net`. It is possible to reuse this + standard device for DPDK vhost, which makes setup a little simpler but it + is better practice to specify an alternative character device in order to + avoid any conflicts if kernel vhost is to be used in parallel. + +1. This step is only needed if using an alternative character device. + + The new character device filename must be specified on the vswitchd + commandline: + + `./vswitchd/ovs-vswitchd --dpdk --cuse_dev_name my-vhost-net -c 0x1 ...` + + Note that the `--cuse_dev_name` argument and associated string must be the first + arguments after `--dpdk` and come before the EAL arguments. In the example + above, the character device to be used will be `/dev/my-vhost-net`. + +2. This step is only needed if reusing the standard character device. It will + conflict with the kernel vhost character device so the user must first + remove it. + + `rm -rf /dev/vhost-net` + +3a. Configure virtio-net adaptors: + The following parameters must be passed to the QEMU binary: + + ``` + -netdev tap,id=,script=no,downscript=no,ifname=,vhost=on + -device virtio-net-pci,netdev=net1,mac= + ``` + + Repeat the above parameters for multiple devices. + + The DPDK vhost library will negiotiate its own features, so they + need not be passed in as command line params. Note that as offloads are + disabled this is the equivalent of setting: + + `csum=off,gso=off,guest_tso4=off,guest_tso6=off,guest_ecn=off` + +3b. If using an alternative character device. It must be also explicitly + passed to QEMU using the `vhostfd` argument: + + ``` + -netdev tap,id=,script=no,downscript=no,ifname=,vhost=on, + vhostfd= + -device virtio-net-pci,netdev=net1,mac= + ``` + + The open file descriptor must be passed to QEMU running as a child + process. This could be done with a simple python script. + + ``` + #!/usr/bin/python + fd = os.open("/dev/usvhost", os.O_RDWR) + subprocess.call("qemu-system-x86_64 .... -netdev tap,id=vhostnet0,\ + vhost=on,vhostfd=" + fd +"...", shell=True) + + Alternatively the the `qemu-wrap.py` script can be used to automate the + requirements specified above and can be used in conjunction with libvirt if + desired. See the "DPDK vhost VM configuration with QEMU wrapper" section + below. + +4. Configure huge pages: + QEMU must allocate the VM's memory on hugetlbfs. Vhost ports access a + virtio-net device's virtual rings and packet buffers mapping the VM's + physical memory on hugetlbfs. To enable vhost-ports to map the VM's + memory into their process address space, pass the following paramters + to QEMU: + + `-object memory-backend-file,id=mem,size=4096M,mem-path=/dev/hugepages, + share=on -numa node,memdev=mem -mem-prealloc` + + +DPDK vhost VM configuration with QEMU wrapper: +---------------------------------------------- + +The QEMU wrapper script automatically detects and calls QEMU with the +necessary parameters. It performs the following actions: + + * Automatically detects the location of the hugetlbfs and inserts this + into the command line parameters. + * Automatically open file descriptors for each virtio-net device and + inserts this into the command line parameters. + * Calls QEMU passing both the command line parameters passed to the + script itself and those it has auto-detected. + +Before use, you **must** edit the configuration parameters section of the +script to point to the correct emulator location and set additional +settings. Of these settings, `emul_path` and `us_vhost_path` **must** be +set. All other settings are optional. + +To use directly from the command line simply pass the wrapper some of the +QEMU parameters: it will configure the rest. For example: + +``` +qemu-wrap.py -cpu host -boot c -hda -m 4096 -smp 4 + --enable-kvm -nographic -vnc none -net none -netdev tap,id=net1, + script=no,downscript=no,ifname=if1,vhost=on -device virtio-net-pci, + netdev=net1,mac=00:00:00:00:00:01 + +DPDK vhost VM configuration with libvirt: +----------------------------------------- + +If you are using libvirt, you must enable libvirt to access the character +device by adding it to controllers cgroup for libvirtd using the following +steps. + + 1. In `/etc/libvirt/qemu.conf` add/edit the following lines: + + ``` + 1) clear_emulator_capabilities = 0 + 2) user = "root" + 3) group = "root" + 4) cgroup_device_acl = [ + "/dev/null", "/dev/full", "/dev/zero", + "/dev/random", "/dev/urandom", + "/dev/ptmx", "/dev/kvm", "/dev/kqemu", + "/dev/rtc", "/dev/hpet", "/dev/net/tun", + "/dev/", + "/dev/hugepages"] + ``` + + refers to "vhost-net" if using the `/dev/vhost-net` + device. If you have specificed a different name on the ovs-vswitchd + commandline using the "--cuse_dev_name" parameter, please specify that + filename instead. + + 2. Disable SELinux or set to permissive mode + + 3. Restart the libvirtd process + For example, on Fedora: + + `systemctl restart libvirtd.service` + +After successfully editing the configuration, you may launch your +vhost-enabled VM. The XML describing the VM can be configured like so +within the section: + + 1. Set up shared hugepages: + + ``` + + + + + + ``` + + 2. Set up your tap devices: + + ``` + + + + + ``` + + Repeat for as many devices as are desired, modifying the id, ifname + and mac as necessary. + + Again, if you are using an alternative character device (other than + `/dev/vhost-net`), please specify the file descriptor like so: + + `` + + Where refers to the open file descriptor of the character device. + Instructions of how to retrieve the file descriptor can be found in the + "DPDK vhost VM configuration" section. + Alternatively, the process is automated with the qemu-wrap.py script, + detailed in the next section. + +Now you may launch your VM using virt-manager, or like so: + + `virsh create my_vhost_vm.xml` + +DPDK vhost VM configuration with libvirt and QEMU wrapper: +---------------------------------------------------------- + +To use the qemu-wrapper script in conjuntion with libvirt, follow the +steps in the previous section before proceeding with the following steps: + + 1. Place `qemu-wrap.py` in libvirtd's binary search PATH ($PATH) + Ideally in the same directory that the QEMU binary is located. + + 2. Ensure that the script has the same owner/group and file permissions + as the QEMU binary. + + 3. Update the VM xml file using "virsh edit VM.xml" + + 1. Set the VM to use the launch script. + Set the emulator path contained in the `` tags. + For example, replace: + + `/usr/bin/qemu-kvm` + + with: + + `/usr/bin/qemu-wrap.py` + + 4. Edit the Configuration Parameters section of the script to point to + the correct emulator location and set any additional options. If you are + using a alternative character device name, please set "us_vhost_path" to the + location of that device. The script will automatically detect and insert + the correct "vhostfd" value in the QEMU command line arguements. + + 5. Use virt-manager to launch the VM + Restrictions: ------------- - - This Support is for Physical NIC. I have tested with Intel NIC only. - Work with 1500 MTU, needs few changes in DPDK lib to fix this issue. - Currently DPDK port does not make use any offload functionality. + - DPDK-vHost support works with 1G huge pages. ivshmem: - The shared memory is currently restricted to the use of a 1GB @@ -311,3 +562,4 @@ Please report problems to bugs@openvswitch.org. [INSTALL.userspace.md]:INSTALL.userspace.md [INSTALL.md]:INSTALL.md [DPDK Linux GSG]: http://www.dpdk.org/doc/guides/linux_gsg/build_dpdk.html#binding-and-unbinding-network-ports-to-from-the-igb-uioor-vfio-modules +[DPDK Docs]: http://dpdk.org/doc diff --git a/Makefile.am b/Makefile.am index 0480d20b5..e1a4e1780 100644 --- a/Makefile.am +++ b/Makefile.am @@ -32,6 +32,10 @@ AM_CFLAGS = -Wstrict-prototypes AM_CFLAGS += $(WARNING_FLAGS) AM_CFLAGS += $(OVS_CFLAGS) +if DPDK_NETDEV +AM_CFLAGS += -D_FILE_OFFSET_BITS=64 +endif + if NDEBUG AM_CPPFLAGS += -DNDEBUG AM_CFLAGS += -fomit-frame-pointer diff --git a/NEWS b/NEWS index 9c7ba62bb..9461f536d 100644 --- a/NEWS +++ b/NEWS @@ -71,6 +71,7 @@ Post-v2.3.0 Auto-Attach. - The default OpenFlow and OVSDB ports are now the IANA-assigned numbers. OpenFlow is 6653 and OVSDB is 6640. + - Support for DPDK vHost. v2.3.0 - 14 Aug 2014 diff --git a/acinclude.m4 b/acinclude.m4 index 18598b333..a56d160d9 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -170,7 +170,7 @@ AC_DEFUN([OVS_CHECK_DPDK], [ DPDK_INCLUDE=$RTE_SDK/include DPDK_LIB_DIR=$RTE_SDK/lib - DPDK_LIB=-lintel_dpdk + DPDK_LIB="-lintel_dpdk -lfuse " ovs_save_CFLAGS="$CFLAGS" ovs_save_LDFLAGS="$LDFLAGS" @@ -214,7 +214,7 @@ AC_DEFUN([OVS_CHECK_DPDK], [ # # These options are specified inside a single -Wl directive to prevent # autotools from reordering them. - DPDK_vswitchd_LDFLAGS=-Wl,--whole-archive,$DPDK_LIB,--no-whole-archive + DPDK_vswitchd_LDFLAGS=-Wl,$DPDK_LIB AC_SUBST([DPDK_vswitchd_LDFLAGS]) AC_DEFINE([DPDK_NETDEV], [1], [System uses the DPDK module.]) else diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c index 1ba83109e..a4775fda0 100644 --- a/lib/netdev-dpdk.c +++ b/lib/netdev-dpdk.c @@ -49,6 +49,7 @@ #include "rte_config.h" #include "rte_mbuf.h" +#include "rte_virtio_net.h" VLOG_DEFINE_THIS_MODULE(dpdk); static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20); @@ -84,6 +85,11 @@ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20); #define TX_HTHRESH 0 /* Default values of TX host threshold reg. */ #define TX_WTHRESH 0 /* Default values of TX write-back threshold reg. */ +#define MAX_PKT_BURST 32 /* Max burst size for RX/TX */ + +/* Character device cuse_dev_name. */ +char *cuse_dev_name = NULL; + static const struct rte_eth_conf port_conf = { .rxmode = { .mq_mode = ETH_MQ_RX_RSS, @@ -131,6 +137,11 @@ enum { DPDK_RING_SIZE = 256 }; BUILD_ASSERT_DECL(IS_POW2(DPDK_RING_SIZE)); enum { DRAIN_TSC = 200000ULL }; +enum dpdk_dev_type { + DPDK_DEV_ETH = 0, + DPDK_DEV_VHOST = 1 +}; + static int rte_eal_init_ret = ENODEV; static struct ovs_mutex dpdk_mutex = OVS_MUTEX_INITIALIZER; @@ -185,6 +196,7 @@ struct netdev_dpdk { struct netdev up; int port_id; int max_packet_len; + enum dpdk_dev_type type; struct dpdk_tx_queue *tx_q; @@ -202,9 +214,12 @@ struct netdev_dpdk { struct rte_eth_link link; int link_reset_cnt; + /* virtio-net structure for vhost device */ + OVSRCU_TYPE(struct virtio_net *) virtio_dev; + /* In dpdk_list. */ struct ovs_list list_node OVS_GUARDED_BY(dpdk_mutex); - rte_spinlock_t dpdkr_tx_lock; + rte_spinlock_t txq_lock; }; struct netdev_rxq_dpdk { @@ -216,14 +231,16 @@ static bool thread_is_pmd(void); static int netdev_dpdk_construct(struct netdev *); +struct virtio_net * netdev_dpdk_get_virtio(const struct netdev_dpdk *dev); + static bool is_dpdk_class(const struct netdev_class *class) { return class->construct == netdev_dpdk_construct; } -/* XXX: use dpdk malloc for entire OVS. infact huge page shld be used - * for all other sengments data, bss and text. */ +/* XXX: use dpdk malloc for entire OVS. in fact huge page should be used + * for all other segments data, bss and text. */ static void * dpdk_rte_mzalloc(size_t sz) @@ -483,7 +500,8 @@ netdev_dpdk_alloc_txq(struct netdev_dpdk *netdev, unsigned int n_txqs) } static int -netdev_dpdk_init(struct netdev *netdev_, unsigned int port_no) +netdev_dpdk_init(struct netdev *netdev_, unsigned int port_no, + enum dpdk_dev_type type) OVS_REQUIRES(dpdk_mutex) { struct netdev_dpdk *netdev = netdev_dpdk_cast(netdev_); @@ -491,20 +509,24 @@ netdev_dpdk_init(struct netdev *netdev_, unsigned int port_no) int err = 0; ovs_mutex_init(&netdev->mutex); - ovs_mutex_lock(&netdev->mutex); /* If the 'sid' is negative, it means that the kernel fails * to obtain the pci numa info. In that situation, always * use 'SOCKET0'. */ - sid = rte_eth_dev_socket_id(port_no); + if (type == DPDK_DEV_ETH) { + sid = rte_eth_dev_socket_id(port_no); + } else { + sid = rte_lcore_to_socket_id(rte_get_master_lcore()); + } + netdev->socket_id = sid < 0 ? SOCKET0 : sid; - netdev_dpdk_alloc_txq(netdev, NR_QUEUE); netdev->port_id = port_no; + netdev->type = type; netdev->flags = 0; netdev->mtu = ETHER_MTU; netdev->max_packet_len = MTU_TO_MAX_LEN(netdev->mtu); - rte_spinlock_init(&netdev->dpdkr_tx_lock); + rte_spinlock_init(&netdev->txq_lock); netdev->dpdk_mp = dpdk_mp_get(netdev->socket_id, netdev->mtu); if (!netdev->dpdk_mp) { @@ -514,9 +536,13 @@ netdev_dpdk_init(struct netdev *netdev_, unsigned int port_no) netdev_->n_txq = NR_QUEUE; netdev_->n_rxq = NR_QUEUE; - err = dpdk_eth_dev_init(netdev); - if (err) { - goto unlock; + + if (type == DPDK_DEV_ETH) { + netdev_dpdk_alloc_txq(netdev, NR_QUEUE); + err = dpdk_eth_dev_init(netdev); + if (err) { + goto unlock; + } } list_push_back(&dpdk_list, &netdev->list_node); @@ -544,6 +570,22 @@ dpdk_dev_parse_name(const char dev_name[], const char prefix[], return 0; } +static int +netdev_dpdk_vhost_construct(struct netdev *netdev_) +{ + int err; + + if (rte_eal_init_ret) { + return rte_eal_init_ret; + } + + ovs_mutex_lock(&dpdk_mutex); + err = netdev_dpdk_init(netdev_, -1, DPDK_DEV_VHOST); + ovs_mutex_unlock(&dpdk_mutex); + + return err; +} + static int netdev_dpdk_construct(struct netdev *netdev) { @@ -561,7 +603,7 @@ netdev_dpdk_construct(struct netdev *netdev) } ovs_mutex_lock(&dpdk_mutex); - err = netdev_dpdk_init(netdev, port_no); + err = netdev_dpdk_init(netdev, port_no, DPDK_DEV_ETH); ovs_mutex_unlock(&dpdk_mutex); return err; } @@ -580,8 +622,23 @@ netdev_dpdk_destruct(struct netdev *netdev_) list_remove(&dev->list_node); dpdk_mp_put(dev->dpdk_mp); ovs_mutex_unlock(&dpdk_mutex); +} - ovs_mutex_destroy(&dev->mutex); +static void +netdev_dpdk_vhost_destruct(struct netdev *netdev_) +{ + struct netdev_dpdk *dev = netdev_dpdk_cast(netdev_); + + /* Can't remove a port while a guest is attached to it. */ + if (netdev_dpdk_get_virtio(dev) != NULL) { + VLOG_ERR("Can not remove port, vhost device still attached"); + return; + } + + ovs_mutex_lock(&dpdk_mutex); + list_remove(&dev->list_node); + dpdk_mp_put(dev->dpdk_mp); + ovs_mutex_unlock(&dpdk_mutex); } static void @@ -635,6 +692,7 @@ netdev_dpdk_set_multiq(struct netdev *netdev_, unsigned int n_txq, netdev->up.n_txq = n_txq; netdev->up.n_rxq = n_rxq; + rte_free(netdev->tx_q); netdev_dpdk_alloc_txq(netdev, n_txq); err = dpdk_eth_dev_init(netdev); @@ -645,6 +703,29 @@ netdev_dpdk_set_multiq(struct netdev *netdev_, unsigned int n_txq, return err; } +static int +netdev_dpdk_vhost_set_multiq(struct netdev *netdev_, unsigned int n_txq, + unsigned int n_rxq) +{ + struct netdev_dpdk *netdev = netdev_dpdk_cast(netdev_); + int err = 0; + + if (netdev->up.n_txq == n_txq && netdev->up.n_rxq == n_rxq) { + return err; + } + + ovs_mutex_lock(&dpdk_mutex); + ovs_mutex_lock(&netdev->mutex); + + netdev->up.n_txq = n_txq; + netdev->up.n_rxq = n_rxq; + + ovs_mutex_unlock(&netdev->mutex); + ovs_mutex_unlock(&dpdk_mutex); + + return err; +} + static struct netdev_rxq * netdev_dpdk_rxq_alloc(void) { @@ -731,6 +812,43 @@ dpdk_queue_flush(struct netdev_dpdk *dev, int qid) dpdk_queue_flush__(dev, qid); } +static bool +is_vhost_running(struct virtio_net *dev) +{ + return (dev != NULL && (dev->flags & VIRTIO_DEV_RUNNING)); +} + +/* + * The receive path for the vhost port is the TX path out from guest. + */ +static int +netdev_dpdk_vhost_rxq_recv(struct netdev_rxq *rxq_, + struct dp_packet **packets, int *c) +{ + struct netdev_rxq_dpdk *rx = netdev_rxq_dpdk_cast(rxq_); + struct netdev *netdev = rx->up.netdev; + struct netdev_dpdk *vhost_dev = netdev_dpdk_cast(netdev); + struct virtio_net *virtio_dev = netdev_dpdk_get_virtio(vhost_dev); + int qid = 1; + uint16_t nb_rx = 0; + + if (OVS_UNLIKELY(!is_vhost_running(virtio_dev))) { + return EAGAIN; + } + + nb_rx = rte_vhost_dequeue_burst(virtio_dev, qid, + vhost_dev->dpdk_mp->mp, + (struct rte_mbuf **)packets, + MAX_PKT_BURST); + if (!nb_rx) { + return EAGAIN; + } + + vhost_dev->stats.rx_packets += (uint64_t)nb_rx; + *c = (int) nb_rx; + return 0; +} + static int netdev_dpdk_rxq_recv(struct netdev_rxq *rxq_, struct dp_packet **packets, int *c) @@ -759,6 +877,38 @@ netdev_dpdk_rxq_recv(struct netdev_rxq *rxq_, struct dp_packet **packets, return 0; } +static void +__netdev_dpdk_vhost_send(struct netdev *netdev, struct dp_packet **pkts, + int cnt, bool may_steal) +{ + struct netdev_dpdk *vhost_dev = netdev_dpdk_cast(netdev); + struct virtio_net *virtio_dev = netdev_dpdk_get_virtio(vhost_dev); + int tx_pkts, i; + + if (OVS_UNLIKELY(!is_vhost_running(virtio_dev))) { + ovs_mutex_lock(&vhost_dev->mutex); + vhost_dev->stats.tx_dropped+= cnt; + ovs_mutex_unlock(&vhost_dev->mutex); + goto out; + } + + /* There is vHost TX single queue, So we need to lock it for TX. */ + rte_spinlock_lock(&vhost_dev->txq_lock); + tx_pkts = rte_vhost_enqueue_burst(virtio_dev, VIRTIO_RXQ, + (struct rte_mbuf **)pkts, cnt); + + vhost_dev->stats.tx_packets += tx_pkts; + vhost_dev->stats.tx_dropped += (cnt - tx_pkts); + rte_spinlock_unlock(&vhost_dev->txq_lock); + +out: + if (may_steal) { + for (i = 0; i < cnt; i++) { + dp_packet_delete(pkts[i]); + } + } +} + inline static void dpdk_queue_pkts(struct netdev_dpdk *dev, int qid, struct rte_mbuf **pkts, int cnt) @@ -790,7 +940,7 @@ dpdk_queue_pkts(struct netdev_dpdk *dev, int qid, /* Tx function. Transmit packets indefinitely */ static void -dpdk_do_tx_copy(struct netdev *netdev, int qid, struct dp_packet ** pkts, +dpdk_do_tx_copy(struct netdev *netdev, int qid, struct dp_packet **pkts, int cnt) OVS_NO_THREAD_SAFETY_ANALYSIS { @@ -840,14 +990,37 @@ dpdk_do_tx_copy(struct netdev *netdev, int qid, struct dp_packet ** pkts, ovs_mutex_unlock(&dev->mutex); } - dpdk_queue_pkts(dev, qid, mbufs, newcnt); - dpdk_queue_flush(dev, qid); + if (dev->type == DPDK_DEV_VHOST) { + __netdev_dpdk_vhost_send(netdev, (struct dp_packet **) mbufs, newcnt, true); + } else { + dpdk_queue_pkts(dev, qid, mbufs, newcnt); + dpdk_queue_flush(dev, qid); + } if (!thread_is_pmd()) { ovs_mutex_unlock(&nonpmd_mempool_mutex); } } +static int +netdev_dpdk_vhost_send(struct netdev *netdev, int qid OVS_UNUSED, struct dp_packet **pkts, + int cnt, bool may_steal) +{ + if (OVS_UNLIKELY(pkts[0]->source != DPBUF_DPDK)) { + int i; + + dpdk_do_tx_copy(netdev, qid, pkts, cnt); + if (may_steal) { + for (i = 0; i < cnt; i++) { + dp_packet_delete(pkts[i]); + } + } + } else { + __netdev_dpdk_vhost_send(netdev, pkts, cnt, may_steal); + } + return 0; +} + static inline void netdev_dpdk_send__(struct netdev_dpdk *dev, int qid, struct dp_packet **pkts, int cnt, bool may_steal) @@ -1001,6 +1174,44 @@ out: static int netdev_dpdk_get_carrier(const struct netdev *netdev_, bool *carrier); +static int +netdev_dpdk_vhost_get_stats(const struct netdev *netdev, + struct netdev_stats *stats) +{ + struct netdev_dpdk *dev = netdev_dpdk_cast(netdev); + + ovs_mutex_lock(&dev->mutex); + memset(stats, 0, sizeof(*stats)); + /* Unsupported Stats */ + stats->rx_errors = UINT64_MAX; + stats->tx_errors = UINT64_MAX; + stats->multicast = UINT64_MAX; + stats->collisions = UINT64_MAX; + stats->rx_crc_errors = UINT64_MAX; + stats->rx_fifo_errors = UINT64_MAX; + stats->rx_frame_errors = UINT64_MAX; + stats->rx_length_errors = UINT64_MAX; + stats->rx_missed_errors = UINT64_MAX; + stats->rx_over_errors = UINT64_MAX; + stats->tx_aborted_errors = UINT64_MAX; + stats->tx_carrier_errors = UINT64_MAX; + stats->tx_errors = UINT64_MAX; + stats->tx_fifo_errors = UINT64_MAX; + stats->tx_heartbeat_errors = UINT64_MAX; + stats->tx_window_errors = UINT64_MAX; + stats->rx_bytes += UINT64_MAX; + stats->rx_dropped += UINT64_MAX; + stats->tx_bytes += UINT64_MAX; + + /* Supported Stats */ + stats->rx_packets += dev->stats.rx_packets; + stats->tx_packets += dev->stats.tx_packets; + stats->tx_dropped += dev->stats.tx_dropped; + ovs_mutex_unlock(&dev->mutex); + + return 0; +} + static int netdev_dpdk_get_stats(const struct netdev *netdev, struct netdev_stats *stats) { @@ -1095,6 +1306,26 @@ netdev_dpdk_get_carrier(const struct netdev *netdev_, bool *carrier) ovs_mutex_lock(&dev->mutex); check_link_status(dev); *carrier = dev->link.link_status; + + ovs_mutex_unlock(&dev->mutex); + + return 0; +} + +static int +netdev_dpdk_vhost_get_carrier(const struct netdev *netdev_, bool *carrier) +{ + struct netdev_dpdk *dev = netdev_dpdk_cast(netdev_); + struct virtio_net *virtio_dev = netdev_dpdk_get_virtio(dev); + + ovs_mutex_lock(&dev->mutex); + + if (is_vhost_running(virtio_dev)) { + *carrier = 1; + } else { + *carrier = 0; + } + ovs_mutex_unlock(&dev->mutex); return 0; @@ -1139,18 +1370,20 @@ netdev_dpdk_update_flags__(struct netdev_dpdk *dev, return 0; } - if (dev->flags & NETDEV_UP) { - err = rte_eth_dev_start(dev->port_id); - if (err) - return -err; - } + if (dev->type == DPDK_DEV_ETH) { + if (dev->flags & NETDEV_UP) { + err = rte_eth_dev_start(dev->port_id); + if (err) + return -err; + } - if (dev->flags & NETDEV_PROMISC) { - rte_eth_promiscuous_enable(dev->port_id); - } + if (dev->flags & NETDEV_PROMISC) { + rte_eth_promiscuous_enable(dev->port_id); + } - if (!(dev->flags & NETDEV_UP)) { - rte_eth_dev_stop(dev->port_id); + if (!(dev->flags & NETDEV_UP)) { + rte_eth_dev_stop(dev->port_id); + } } return 0; @@ -1261,6 +1494,134 @@ netdev_dpdk_set_admin_state(struct unixctl_conn *conn, int argc, unixctl_command_reply(conn, "OK"); } +/* + * Set virtqueue flags so that we do not receive interrupts. + */ +static void +set_irq_status(struct virtio_net *dev) +{ + dev->virtqueue[VIRTIO_RXQ]->used->flags = VRING_USED_F_NO_NOTIFY; + dev->virtqueue[VIRTIO_TXQ]->used->flags = VRING_USED_F_NO_NOTIFY; +} + +/* + * A new virtio-net device is added to a vhost port. + */ +static int +new_device(struct virtio_net *dev) +{ + struct netdev_dpdk *netdev; + bool exists = false; + + ovs_mutex_lock(&dpdk_mutex); + /* Add device to the vhost port with the same name as that passed down. */ + LIST_FOR_EACH(netdev, list_node, &dpdk_list) { + if (strncmp(dev->ifname, netdev->up.name, IFNAMSIZ) == 0) { + ovs_mutex_lock(&netdev->mutex); + ovsrcu_set(&netdev->virtio_dev, dev); + ovs_mutex_unlock(&netdev->mutex); + exists = true; + dev->flags |= VIRTIO_DEV_RUNNING; + /* Disable notifications. */ + set_irq_status(dev); + break; + } + } + ovs_mutex_unlock(&dpdk_mutex); + + if (!exists) { + VLOG_INFO("vHost Device '%s' (%ld) can't be added - name not found", + dev->ifname, dev->device_fh); + + return -1; + } + + VLOG_INFO("vHost Device '%s' (%ld) has been added", + dev->ifname, dev->device_fh); + return 0; +} + +/* + * Remove a virtio-net device from the specific vhost port. Use dev->remove + * flag to stop any more packets from being sent or received to/from a VM and + * ensure all currently queued packets have been sent/received before removing + * the device. + */ +static void +destroy_device(volatile struct virtio_net *dev) +{ + struct netdev_dpdk *vhost_dev; + + ovs_mutex_lock(&dpdk_mutex); + LIST_FOR_EACH (vhost_dev, list_node, &dpdk_list) { + if (netdev_dpdk_get_virtio(vhost_dev) == dev) { + + ovs_mutex_lock(&vhost_dev->mutex); + dev->flags &= ~VIRTIO_DEV_RUNNING; + ovsrcu_set(&vhost_dev->virtio_dev, NULL); + ovs_mutex_unlock(&vhost_dev->mutex); + + /* + * Wait for other threads to quiesce before + * setting the virtio_dev to NULL. + */ + ovsrcu_synchronize(); + } + } + ovs_mutex_unlock(&dpdk_mutex); + + VLOG_INFO("vHost Device '%s' (%ld) has been removed", + dev->ifname, dev->device_fh); +} + +struct virtio_net * +netdev_dpdk_get_virtio(const struct netdev_dpdk *dev) +{ + return ovsrcu_get(struct virtio_net *, &dev->virtio_dev); +} + +/* + * These callbacks allow virtio-net devices to be added to vhost ports when + * configuration has been fully complete. + */ +const struct virtio_net_device_ops virtio_net_device_ops = +{ + .new_device = new_device, + .destroy_device = destroy_device, +}; + +static void * +start_cuse_session_loop(void *dummy OVS_UNUSED) +{ + pthread_detach(pthread_self()); + rte_vhost_driver_session_start(); + return NULL; +} + +static int +dpdk_vhost_class_init(void) +{ + pthread_t thread; + int err = -1; + + rte_vhost_driver_callback_register(&virtio_net_device_ops); + + /* Register CUSE device to handle IOCTLs. + * Unless otherwise specified on the vswitchd command line, cuse_dev_name + * is set to vhost-net. + */ + err = rte_vhost_driver_register(cuse_dev_name); + + if (err != 0) { + VLOG_ERR("CUSE device setup failure."); + return -1; + } + + /* start_cuse_session_loop blocks OVS RCU quiescent state, so directly use + * pthread API. */ + return pthread_create(&thread, NULL, start_cuse_session_loop, NULL); +} + static void dpdk_common_init(void) { @@ -1345,7 +1706,7 @@ dpdk_ring_open(const char dev_name[], unsigned int *eth_port_id) OVS_REQUIRES(dp /* look through our list to find the device */ LIST_FOR_EACH (ivshmem, list_node, &dpdk_ring_list) { if (ivshmem->user_port_id == port_no) { - VLOG_INFO("Found dpdk ring device %s:\n", dev_name); + VLOG_INFO("Found dpdk ring device %s:", dev_name); *eth_port_id = ivshmem->eth_port_id; /* really all that is needed */ return 0; } @@ -1361,9 +1722,9 @@ netdev_dpdk_ring_send(struct netdev *netdev, int qid OVS_UNUSED, struct netdev_dpdk *dev = netdev_dpdk_cast(netdev); /* DPDK Rings have a single TX queue, Therefore needs locking. */ - rte_spinlock_lock(&dev->dpdkr_tx_lock); + rte_spinlock_lock(&dev->txq_lock); netdev_dpdk_send__(dev, 0, pkts, cnt, may_steal); - rte_spinlock_unlock(&dev->dpdkr_tx_lock); + rte_spinlock_unlock(&dev->txq_lock); return 0; } @@ -1384,14 +1745,15 @@ netdev_dpdk_ring_construct(struct netdev *netdev) goto unlock_dpdk; } - err = netdev_dpdk_init(netdev, port_no); + err = netdev_dpdk_init(netdev, port_no, DPDK_DEV_ETH); unlock_dpdk: ovs_mutex_unlock(&dpdk_mutex); return err; } -#define NETDEV_DPDK_CLASS(NAME, INIT, CONSTRUCT, MULTIQ, SEND) \ +#define NETDEV_DPDK_CLASS(NAME, INIT, CONSTRUCT, DESTRUCT, MULTIQ, SEND, \ + GET_CARRIER, GET_STATS, GET_FEATURES, GET_STATUS, RXQ_RECV) \ { \ NAME, \ INIT, /* init */ \ @@ -1400,14 +1762,14 @@ unlock_dpdk: \ netdev_dpdk_alloc, \ CONSTRUCT, \ - netdev_dpdk_destruct, \ + DESTRUCT, \ netdev_dpdk_dealloc, \ netdev_dpdk_get_config, \ NULL, /* netdev_dpdk_set_config */ \ NULL, /* get_tunnel_config */ \ - NULL, /* build header */ \ - NULL, /* push header */ \ - NULL, /* pop header */ \ + NULL, /* build header */ \ + NULL, /* push header */ \ + NULL, /* pop header */ \ netdev_dpdk_get_numa_id, /* get_numa_id */ \ MULTIQ, /* set_multiq */ \ \ @@ -1419,11 +1781,11 @@ unlock_dpdk: netdev_dpdk_get_mtu, \ netdev_dpdk_set_mtu, \ netdev_dpdk_get_ifindex, \ - netdev_dpdk_get_carrier, \ + GET_CARRIER, \ netdev_dpdk_get_carrier_resets, \ netdev_dpdk_set_miimon, \ - netdev_dpdk_get_stats, \ - netdev_dpdk_get_features, \ + GET_STATS, \ + GET_FEATURES, \ NULL, /* set_advertisements */ \ \ NULL, /* set_policing */ \ @@ -1445,7 +1807,7 @@ unlock_dpdk: NULL, /* get_in6 */ \ NULL, /* add_router */ \ NULL, /* get_next_hop */ \ - netdev_dpdk_get_status, \ + GET_STATUS, \ NULL, /* arp_lookup */ \ \ netdev_dpdk_update_flags, \ @@ -1454,7 +1816,7 @@ unlock_dpdk: netdev_dpdk_rxq_construct, \ netdev_dpdk_rxq_destruct, \ netdev_dpdk_rxq_dealloc, \ - netdev_dpdk_rxq_recv, \ + RXQ_RECV, \ NULL, /* rx_wait */ \ NULL, /* rxq_drain */ \ } @@ -1463,20 +1825,48 @@ int dpdk_init(int argc, char **argv) { int result; + int base = 0; + char *pragram_name = argv[0]; if (argc < 2 || strcmp(argv[1], "--dpdk")) return 0; - /* Make sure program name passed to rte_eal_init() is vswitchd. */ - argv[1] = argv[0]; - + /* Remove the --dpdk argument from arg list.*/ argc--; argv++; + /* If the cuse_dev_name parameter has been provided, set 'cuse_dev_name' to + * this string if it meets the correct criteria. Otherwise, set it to the + * default (vhost-net). + */ + if (!strcmp(argv[1], "--cuse_dev_name") && + (strlen(argv[2]) <= NAME_MAX)) { + + cuse_dev_name = strdup(argv[2]); + + /* Remove the cuse_dev_name configuration parameters from the argument + * list, so that the correct elements are passed to the DPDK + * initialization function + */ + argc -= 2; + argv += 2; /* Increment by two to bypass the cuse_dev_name arguments */ + base = 2; + + VLOG_ERR("User-provided cuse_dev_name in use: /dev/%s", cuse_dev_name); + } else { + cuse_dev_name = "vhost-net"; + VLOG_INFO("No cuse_dev_name provided - defaulting to /dev/vhost-net"); + } + + /* Keep the program name argument as this is needed for call to + * rte_eal_init() + */ + argv[0] = pragram_name; + /* Make sure things are initialized ... */ result = rte_eal_init(argc, argv); if (result < 0) { - ovs_abort(result, "Cannot init EAL\n"); + ovs_abort(result, "Cannot init EAL"); } rte_memzone_dump(stdout); @@ -1489,7 +1879,7 @@ dpdk_init(int argc, char **argv) /* We are called from the main thread here */ thread_set_nonpmd(); - return result + 1; + return result + 1 + base; } const struct netdev_class dpdk_class = @@ -1497,16 +1887,42 @@ const struct netdev_class dpdk_class = "dpdk", NULL, netdev_dpdk_construct, + netdev_dpdk_destruct, netdev_dpdk_set_multiq, - netdev_dpdk_eth_send); + netdev_dpdk_eth_send, + netdev_dpdk_get_carrier, + netdev_dpdk_get_stats, + netdev_dpdk_get_features, + netdev_dpdk_get_status, + netdev_dpdk_rxq_recv); const struct netdev_class dpdk_ring_class = NETDEV_DPDK_CLASS( "dpdkr", NULL, netdev_dpdk_ring_construct, + netdev_dpdk_destruct, + NULL, + netdev_dpdk_ring_send, + netdev_dpdk_get_carrier, + netdev_dpdk_get_stats, + netdev_dpdk_get_features, + netdev_dpdk_get_status, + netdev_dpdk_rxq_recv); + +const struct netdev_class dpdk_vhost_class = + NETDEV_DPDK_CLASS( + "dpdkvhost", + dpdk_vhost_class_init, + netdev_dpdk_vhost_construct, + netdev_dpdk_vhost_destruct, + netdev_dpdk_vhost_set_multiq, + netdev_dpdk_vhost_send, + netdev_dpdk_vhost_get_carrier, + netdev_dpdk_vhost_get_stats, + NULL, NULL, - netdev_dpdk_ring_send); + netdev_dpdk_vhost_rxq_recv); void netdev_dpdk_register(void) @@ -1521,6 +1937,7 @@ netdev_dpdk_register(void) dpdk_common_init(); netdev_register_provider(&dpdk_class); netdev_register_provider(&dpdk_ring_class); + netdev_register_provider(&dpdk_vhost_class); ovsthread_once_done(&once); } } diff --git a/lib/netdev.c b/lib/netdev.c index b76da139a..149b39a77 100644 --- a/lib/netdev.c +++ b/lib/netdev.c @@ -108,7 +108,8 @@ bool netdev_is_pmd(const struct netdev *netdev) { return (!strcmp(netdev->netdev_class->type, "dpdk") || - !strcmp(netdev->netdev_class->type, "dpdkr")); + !strcmp(netdev->netdev_class->type, "dpdkr") || + !strcmp(netdev->netdev_class->type, "dpdkvhost")); } static void diff --git a/utilities/automake.mk b/utilities/automake.mk index 55bf44967..8b55e2d5d 100644 --- a/utilities/automake.mk +++ b/utilities/automake.mk @@ -46,7 +46,8 @@ EXTRA_DIST += \ utilities/ovs-save \ utilities/ovs-tcpundump.in \ utilities/ovs-test.in \ - utilities/ovs-vlan-test.in + utilities/ovs-vlan-test.in \ + utilities/qemu-wrap.py MAN_ROOTS += \ utilities/ovs-appctl.8.in \ utilities/ovs-benchmark.1.in \ diff --git a/utilities/qemu-wrap.py b/utilities/qemu-wrap.py new file mode 100755 index 000000000..5cee849ae --- /dev/null +++ b/utilities/qemu-wrap.py @@ -0,0 +1,389 @@ +#!/usr/bin/python +# +# BSD LICENSE +# +# Copyright(c) 2010-2014 Intel Corporation. All rights reserved. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +##################################################################### +# This script is designed to modify the call to the QEMU emulator +# to support userspace vhost when starting a guest machine through +# libvirt with vhost enabled. The steps to enable this are as follows +# and should be run as root: +# +# 1. Place this script in a libvirtd's binary search PATH ($PATH) +# A good location would be in the same directory that the QEMU +# binary is located +# +# 2. Ensure that the script has the same owner/group and file +# permissions as the QEMU binary +# +# 3. Update the VM xml file using "virsh edit VM.xml" +# +# 3.a) Set the VM to use the launch script +# +# Set the emulator path contained in the +# tags +# +# e.g replace /usr/bin/qemu-kvm +# with /usr/bin/qemu-wrap.py +# +# 3.b) Set the VM's device's to use vhost-net offload +# +# +# +# +# +# +# 4. Enable libvirt to access our userpace device file by adding it to +# controllers cgroup for libvirtd using the following steps +# +# 4.a) In /etc/libvirt/qemu.conf add/edit the following lines: +# 1) cgroup_controllers = [ ... "devices", ... ] +# 2) clear_emulator_capabilities = 0 +# 3) user = "root" +# 4) group = "root" +# 5) cgroup_device_acl = [ +# "/dev/null", "/dev/full", "/dev/zero", +# "/dev/random", "/dev/urandom", +# "/dev/ptmx", "/dev/kvm", "/dev/kqemu", +# "/dev/rtc", "/dev/hpet", "/dev/net/tun", +# "/dev/-", +# "/dev/hugepages" +# ] +# +# 4.b) Disable SELinux or set to permissive mode +# +# 4.c) Mount cgroup device controller +# "mkdir /dev/cgroup" +# "mount -t cgroup none /dev/cgroup -o devices" +# +# 4.d) Set hugetlbfs_mount variable - ( Optional ) +# VMs using userspace vhost must use hugepage backed +# memory. This can be enabled in the libvirt XML +# config by adding a memory backing section to the +# XML config e.g. +# +# +# +# This memory backing section should be added after the +# and sections. This will add +# flags "-mem-prealloc -mem-path " to the QEMU +# command line. The hugetlbfs_mount variable can be used +# to override the default passed through by libvirt. +# +# if "-mem-prealloc" or "-mem-path " are not passed +# through and a vhost device is detected then these options will +# be automatically added by this script. This script will detect +# the system hugetlbfs mount point to be used for . The +# default for this script can be overidden by the +# hugetlbfs_dir variable in the configuration section of this script. +# +# +# 4.e) Restart the libvirtd system process +# e.g. on Fedora "systemctl restart libvirtd.service" +# +# +# 4.f) Edit the Configuration Parameters section of this script +# to point to the correct emulator location and set any +# addition options +# +# The script modifies the libvirtd Qemu call by modifying/adding +# options based on the configuration parameters below. +# NOTE: +# emul_path and us_vhost_path must be set +# All other parameters are optional +##################################################################### + + +############################################# +# Configuration Parameters +############################################# +#Path to QEMU binary +emul_path = "/usr/local/bin/qemu-system-x86_64" + +#Path to userspace vhost device file +# This filename should match the --dev-basename --dev-index parameters of +# the command used to launch the userspace vhost sample application e.g. +# if the sample app lauch command is: +# ./build/vhost-switch ..... --dev-basename usvhost --dev-index 1 +# then this variable should be set to: +# us_vhost_path = "/dev/usvhost-1" +us_vhost_path = "/dev/usvhost-1" + +#List of additional user defined emulation options. These options will +#be added to all Qemu calls +emul_opts_user = [] + +#List of additional user defined emulation options for vhost only. +#These options will only be added to vhost enabled guests +emul_opts_user_vhost = [] + +#For all VHOST enabled VMs, the VM memory is preallocated from hugetlbfs +# Set this variable to one to enable this option for all VMs +use_huge_all = 0 + +#Instead of autodetecting, override the hugetlbfs directory by setting +#this variable +hugetlbfs_dir = "" + +############################################# + + +############################################# +# ****** Do Not Modify Below this Line ****** +############################################# + +import sys, os, subprocess +import time +import signal + + +#List of open userspace vhost file descriptors +fd_list = [] + +#additional virtio device flags when using userspace vhost +vhost_flags = [ "csum=off", + "gso=off", + "guest_tso4=off", + "guest_tso6=off", + "guest_ecn=off" + ] + +#String of the path to the Qemu process pid +qemu_pid = "/tmp/%d-qemu.pid" % os.getpid() + +############################################# +# Signal haldler to kill Qemu subprocess +############################################# +def kill_qemu_process(signum, stack): + pidfile = open(qemu_pid, 'r') + pid = int(pidfile.read()) + os.killpg(pid, signal.SIGTERM) + pidfile.close() + + +############################################# +# Find the system hugefile mount point. +# Note: +# if multiple hugetlbfs mount points exist +# then the first one found will be used +############################################# +def find_huge_mount(): + + if (len(hugetlbfs_dir)): + return hugetlbfs_dir + + huge_mount = "" + + if (os.access("/proc/mounts", os.F_OK)): + f = open("/proc/mounts", "r") + line = f.readline() + while line: + line_split = line.split(" ") + if line_split[2] == 'hugetlbfs': + huge_mount = line_split[1] + break + line = f.readline() + else: + print "/proc/mounts not found" + exit (1) + + f.close + if len(huge_mount) == 0: + print "Failed to find hugetlbfs mount point" + exit (1) + + return huge_mount + + +############################################# +# Get a userspace Vhost file descriptor +############################################# +def get_vhost_fd(): + + if (os.access(us_vhost_path, os.F_OK)): + fd = os.open( us_vhost_path, os.O_RDWR) + else: + print ("US-Vhost file %s not found" %us_vhost_path) + exit (1) + + return fd + + +############################################# +# Check for vhostfd. if found then replace +# with our own vhost fd and append any vhost +# flags onto the end +############################################# +def modify_netdev_arg(arg): + + global fd_list + vhost_in_use = 0 + s = '' + new_opts = [] + netdev_opts = arg.split(",") + + for opt in netdev_opts: + #check if vhost is used + if "vhost" == opt[:5]: + vhost_in_use = 1 + else: + new_opts.append(opt) + + #if using vhost append vhost options + if vhost_in_use == 1: + #append vhost on option + new_opts.append('vhost=on') + #append vhostfd ption + new_fd = get_vhost_fd() + new_opts.append('vhostfd=' + str(new_fd)) + fd_list.append(new_fd) + + #concatenate all options + for opt in new_opts: + if len(s) > 0: + s+=',' + + s+=opt + + return s + + +############################################# +# Main +############################################# +def main(): + + global fd_list + global vhost_in_use + new_args = [] + num_cmd_args = len(sys.argv) + emul_call = '' + mem_prealloc_set = 0 + mem_path_set = 0 + num = 0; + + #parse the parameters + while (num < num_cmd_args): + arg = sys.argv[num] + + #Check netdev +1 parameter for vhostfd + if arg == '-netdev': + num_vhost_devs = len(fd_list) + new_args.append(arg) + + num+=1 + arg = sys.argv[num] + mod_arg = modify_netdev_arg(arg) + new_args.append(mod_arg) + + #append vhost flags if this is a vhost device + # and -device is the next arg + # i.e -device -opt1,-opt2,...,-opt3,%vhost + if (num_vhost_devs < len(fd_list)): + num+=1 + arg = sys.argv[num] + if arg == '-device': + new_args.append(arg) + num+=1 + new_arg = sys.argv[num] + for flag in vhost_flags: + new_arg = ''.join([new_arg,',',flag]) + new_args.append(new_arg) + else: + new_args.append(arg) + elif arg == '-mem-prealloc': + mem_prealloc_set = 1 + new_args.append(arg) + elif arg == '-mem-path': + mem_path_set = 1 + new_args.append(arg) + + else: + new_args.append(arg) + + num+=1 + + #Set Qemu binary location + emul_call+=emul_path + emul_call+=" " + + #Add prealloc mem options if using vhost and not already added + if ((len(fd_list) > 0) and (mem_prealloc_set == 0)): + emul_call += "-mem-prealloc " + + #Add mempath mem options if using vhost and not already added + if ((len(fd_list) > 0) and (mem_path_set == 0)): + #Detect and add hugetlbfs mount point + mp = find_huge_mount() + mp = "".join(["-mem-path ", mp]) + emul_call += mp + emul_call += " " + + #add user options + for opt in emul_opts_user: + emul_call += opt + emul_call += " " + + #Add add user vhost only options + if len(fd_list) > 0: + for opt in emul_opts_user_vhost: + emul_call += opt + emul_call += " " + + #Add updated libvirt options + iter_args = iter(new_args) + #skip 1st arg i.e. call to this script + next(iter_args) + for arg in iter_args: + emul_call+=str(arg) + emul_call+= " " + + emul_call += "-pidfile %s " % qemu_pid + #Call QEMU + process = subprocess.Popen(emul_call, shell=True, preexec_fn=os.setsid) + + for sig in [signal.SIGTERM, signal.SIGINT, signal.SIGHUP, signal.SIGQUIT]: + signal.signal(sig, kill_qemu_process) + + process.wait() + + #Close usvhost files + for fd in fd_list: + os.close(fd) + #Cleanup temporary files + if os.access(qemu_pid, os.F_OK): + os.remove(qemu_pid) + + + +if __name__ == "__main__": + main() diff --git a/vswitchd/ovs-vswitchd.c b/vswitchd/ovs-vswitchd.c index eda4aab21..44d44f043 100644 --- a/vswitchd/ovs-vswitchd.c +++ b/vswitchd/ovs-vswitchd.c @@ -252,11 +252,13 @@ usage(void) daemon_usage(); vlog_usage(); printf("\nDPDK options:\n" - " --dpdk options Initialize DPDK datapath.\n"); + " --dpdk options Initialize DPDK datapath.\n" + " --cuse_dev_name BASENAME override default character device name\n" + " for use with userspace vHost.\n"); printf("\nOther options:\n" - " --unixctl=SOCKET override default control socket name\n" - " -h, --help display this help message\n" - " -V, --version display version information\n"); + " --unixctl=SOCKET override default control socket name\n" + " -h, --help display this help message\n" + " -V, --version display version information\n"); exit(EXIT_SUCCESS); } -- cgit v1.2.1 From c557ca04169bbe0af253bd910a5328ac3eee98e7 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Thu, 19 Mar 2015 23:22:05 -0700 Subject: ovs-vsctl: Create AutoAttach records on demand, for backward compatibility. The AutoAttach table is new in OVS 2.3.90, but ovs-vsctl was creating a record in the table unconditionally whenever it created a new bridge. This caused a gratuitous incompatibility with older databases, which can be a problem during upgrade. This commit switches to creating the AutoAttaach record for a bridge lazily, only when the first mapping is created for the bridge. VMware-BZ: #1413562 CC: Dennis Flynn Reported-by: Alex Wang Signed-off-by: Ben Pfaff Acked-by: Justin Pettit --- utilities/ovs-vsctl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/utilities/ovs-vsctl.c b/utilities/ovs-vsctl.c index 1abefb440..fa73b008e 100644 --- a/utilities/ovs-vsctl.c +++ b/utilities/ovs-vsctl.c @@ -1807,7 +1807,6 @@ cmd_add_br(struct vsctl_context *ctx) if (!parent_name) { struct ovsrec_port *port; - struct ovsrec_autoattach *aa; struct ovsrec_bridge *br; iface = ovsrec_interface_insert(ctx->txn); @@ -1818,12 +1817,9 @@ cmd_add_br(struct vsctl_context *ctx) ovsrec_port_set_name(port, br_name); ovsrec_port_set_interfaces(port, &iface, 1); - aa = ovsrec_autoattach_insert(ctx->txn); - br = ovsrec_bridge_insert(ctx->txn); ovsrec_bridge_set_name(br, br_name); ovsrec_bridge_set_ports(br, &port, 1); - ovsrec_bridge_set_auto_attach(br, aa); ovs_insert_bridge(ctx->ovs, br); } else { @@ -2732,6 +2728,10 @@ cmd_add_aa_mapping(struct vsctl_context *ctx) } if (br && br->br_cfg) { + if (!br->br_cfg->auto_attach) { + struct ovsrec_autoattach *aa = ovsrec_autoattach_insert(ctx->txn); + ovsrec_bridge_set_auto_attach(br->br_cfg, aa); + } autoattach_insert_mapping(br->br_cfg->auto_attach, isid, vlan); } } -- cgit v1.2.1 From d6f115f56a88d66f3f6b5f657a45ce6e37099702 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Thu, 19 Mar 2015 23:39:30 -0700 Subject: ovs-vsctl: Only monitor AutoAttach columns when useful. Otherwise this creates a gratuitous incompatibility with older databases, which can be a problem in upgrade situations. VMware-BZ: #1413562 Reported-by: Alex Wang Signed-off-by: Ben Pfaff Acked-by: Justin Pettit --- utilities/ovs-vsctl.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/utilities/ovs-vsctl.c b/utilities/ovs-vsctl.c index fa73b008e..009a8caad 100644 --- a/utilities/ovs-vsctl.c +++ b/utilities/ovs-vsctl.c @@ -1185,7 +1185,6 @@ pre_get_info(struct vsctl_context *ctx) ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_controller); ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_fail_mode); ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_ports); - ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_auto_attach); ovsdb_idl_add_column(ctx->idl, &ovsrec_port_col_name); ovsdb_idl_add_column(ctx->idl, &ovsrec_port_col_fake_bridge); @@ -1194,7 +1193,6 @@ pre_get_info(struct vsctl_context *ctx) ovsdb_idl_add_column(ctx->idl, &ovsrec_interface_col_name); - ovsdb_idl_add_column(ctx->idl, &ovsrec_autoattach_col_mappings); ovsdb_idl_add_column(ctx->idl, &ovsrec_interface_col_ofport); } @@ -2806,6 +2804,7 @@ pre_aa_mapping(struct vsctl_context *ctx) { pre_get_info(ctx); + ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_auto_attach); ovsdb_idl_add_column(ctx->idl, &ovsrec_autoattach_col_mappings); } @@ -4678,7 +4677,7 @@ static const struct vsctl_command_syntax all_commands[] = { cmd_set_ssl, NULL, "--bootstrap", RW}, /* Auto Attach commands. */ - {"add-aa-mapping", 3, 3, "BRIDGE ARG ARG", pre_get_info, cmd_add_aa_mapping, + {"add-aa-mapping", 3, 3, "BRIDGE ARG ARG", pre_aa_mapping, cmd_add_aa_mapping, NULL, "", RW}, {"del-aa-mapping", 3, 3, "BRIDGE ARG ARG", pre_aa_mapping, cmd_del_aa_mapping, NULL, "", RW}, -- cgit v1.2.1 From 3c94676c3727166384372b5dce3de3184ad8ae16 Mon Sep 17 00:00:00 2001 From: Daniele Di Proietto Date: Fri, 20 Mar 2015 06:02:13 -0700 Subject: acinclude.m4: Restore --whole-archive option for DPDK. The --whole-archive option is required to link vswitchd with DPDK, otherwise the PMD drivers are not going to be included. Omitting the option is not going to cause build failures, but OVS won't be able to use most physical NICs. Signed-off-by: Daniele Di Proietto Acked-by: Pravin B Shelar --- acinclude.m4 | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/acinclude.m4 b/acinclude.m4 index a56d160d9..5ed70c172 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -170,7 +170,8 @@ AC_DEFUN([OVS_CHECK_DPDK], [ DPDK_INCLUDE=$RTE_SDK/include DPDK_LIB_DIR=$RTE_SDK/lib - DPDK_LIB="-lintel_dpdk -lfuse " + DPDK_LIB="-lintel_dpdk" + DPDK_EXTRA_LIB="-lfuse" ovs_save_CFLAGS="$CFLAGS" ovs_save_LDFLAGS="$LDFLAGS" @@ -187,7 +188,7 @@ AC_DEFUN([OVS_CHECK_DPDK], [ found=false save_LIBS=$LIBS for extras in "" "-ldl"; do - LIBS="$DPDK_LIB $extras $save_LIBS" + LIBS="$DPDK_LIB $extras $save_LIBS $DPDK_EXTRA_LIB" AC_LINK_IFELSE( [AC_LANG_PROGRAM([#include #include ], @@ -206,7 +207,7 @@ AC_DEFUN([OVS_CHECK_DPDK], [ OVS_LDFLAGS="$OVS_LDFLAGS -L$DPDK_LIB_DIR" OVS_CFLAGS="$OVS_CFLAGS -I$DPDK_INCLUDE" - # DPDK 1.7 pmd drivers are not linked unless --whole-archive is used. + # DPDK pmd drivers are not linked unless --whole-archive is used. # # This happens because the rest of the DPDK code doesn't use any symbol in # the pmd driver objects, and the drivers register themselves using an @@ -214,7 +215,7 @@ AC_DEFUN([OVS_CHECK_DPDK], [ # # These options are specified inside a single -Wl directive to prevent # autotools from reordering them. - DPDK_vswitchd_LDFLAGS=-Wl,$DPDK_LIB + DPDK_vswitchd_LDFLAGS=-Wl,--whole-archive,$DPDK_LIB,--no-whole-archive AC_SUBST([DPDK_vswitchd_LDFLAGS]) AC_DEFINE([DPDK_NETDEV], [1], [System uses the DPDK module.]) else -- cgit v1.2.1 From 777cb78767fd0ca821dad79691ee3200de66f06e Mon Sep 17 00:00:00 2001 From: Daniele Di Proietto Date: Fri, 20 Mar 2015 06:02:14 -0700 Subject: DPDK: Update documentation and travis build for vhost. DPDK vhost support is mandatory to compile OVS with DPDK. This commit updates INSTALL.DPDK.md and the travis build procedure to reflect that. Signed-off-by: Daniele Di Proietto Acked-by: Pravin B Shelar --- .travis/build.sh | 1 + .travis/prepare.sh | 3 +++ INSTALL.DPDK.md | 21 +++++++++------------ 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/.travis/build.sh b/.travis/build.sh index 942265af3..b6b701c3a 100755 --- a/.travis/build.sh +++ b/.travis/build.sh @@ -48,6 +48,7 @@ function install_dpdk() fi find ./ -type f | xargs sed -i 's/max-inline-insns-single=100/max-inline-insns-single=400/' sed -ri 's,(CONFIG_RTE_BUILD_COMBINE_LIBS=).*,\1y,' config/common_linuxapp + sed -ri 's,(CONFIG_RTE_LIBRTE_VHOST=).*,\1y,' config/common_linuxapp sed -ri '/CONFIG_RTE_LIBNAME/a CONFIG_RTE_BUILD_FPIC=y' config/common_linuxapp sed -ri '/EXECENV_CFLAGS = -pthread -fPIC/{s/$/\nelse ifeq ($(CONFIG_RTE_BUILD_FPIC),y)/;s/$/\nEXECENV_CFLAGS = -pthread -fPIC/}' mk/exec-env/linuxapp/rte.vars.mk make config CC=gcc T=x86_64-native-linuxapp-gcc diff --git a/.travis/prepare.sh b/.travis/prepare.sh index a78282be5..cda80c22b 100755 --- a/.travis/prepare.sh +++ b/.travis/prepare.sh @@ -3,6 +3,9 @@ sudo apt-get update -qq sudo apt-get install -qq libssl-dev llvm-dev sudo apt-get install -qq gcc-multilib +if [ "$DPDK" ]; then + sudo apt-get install -qq libfuse-dev +fi git clone git://git.kernel.org/pub/scm/devel/sparse/chrisl/sparse.git cd sparse && make && sudo make install PREFIX=/usr && cd .. diff --git a/INSTALL.DPDK.md b/INSTALL.DPDK.md index a3e2a1db8..5b6127233 100644 --- a/INSTALL.DPDK.md +++ b/INSTALL.DPDK.md @@ -16,8 +16,7 @@ OVS needs a system with 1GB hugepages support. Building and Installing: ------------------------ -Required DPDK 1.8.0 -Optional `fuse`, `fuse-devel` +Required DPDK 1.8.0, `fuse`, `fuse-devel` (`libfuse-dev` on Debian/Ubuntu) 1. Configure build & install DPDK: 1. Set `$DPDK_DIR` @@ -32,7 +31,12 @@ Optional `fuse`, `fuse-devel` `CONFIG_RTE_BUILD_COMBINE_LIBS=y` - Then run `make install` to build and isntall the library. + Update `config/common_linuxapp` so that DPDK is built with vhost + libraries: + + `CONFIG_RTE_LIBRTE_VHOST=y` + + Then run `make install` to build and install the library. For default install without IVSHMEM: `make install T=x86_64-native-linuxapp-gcc` @@ -300,18 +304,11 @@ in future releases when supported in DPDK and that vhost-cuse will eventually be deprecated. See [DPDK Docs] for more info on vhost. Prerequisites: -1. DPDK 1.8 with vhost support enabled and recompile OVS as above. - - Update `config/common_linuxapp` so that DPDK is built with vhost - libraries: - - `CONFIG_RTE_LIBRTE_VHOST=y` - -2. Insert the Cuse module: +1. Insert the Cuse module: `modprobe cuse` -3. Build and insert the `eventfd_link` module: +2. Build and insert the `eventfd_link` module: `cd $DPDK_DIR/lib/librte_vhost/eventfd_link/` `make` -- cgit v1.2.1 From bb5dbe78592b3f39f0e7e6361c8796a5023363e5 Mon Sep 17 00:00:00 2001 From: Alex Wang Date: Fri, 13 Mar 2015 14:47:25 -0700 Subject: ovs-vsctl-bashcomp: Avoid setting the COMP_WORDBREAKS. Modifying $COMP_WORDBREAKS in completion script is not the recommended as it is a global variable and the modification could affect the behavior of other completion scripts. As a workaround, this commit uses the _get_comp_words_by_ref which allows user to exclude characters out of $COMP_WORDBREAKS and reassemble input command line. However, as a side effect, the bash completion module cannot handle characters defined in $COMP_WORDBREAKS (e.g. ':' and '=') correctly in the resulting completions. Thusly, we need to trim the colon-word and equal-word prefixes from reply. Signed-off-by: Alex Wang --- tests/completion.at | 10 +++---- utilities/ovs-vsctl-bashcomp.bash | 55 +++++++++++++++++++++++++++++++++++---- 2 files changed, 55 insertions(+), 10 deletions(-) diff --git a/tests/completion.at b/tests/completion.at index d3b280046..0aca7aabb 100644 --- a/tests/completion.at +++ b/tests/completion.at @@ -608,7 +608,7 @@ AT_CHECK_UNQUOTED([ovs-vsctl-bashcomp.bash test "add Bridge br0 other_config ran [0], [dnl ${MATCH} ]) -MATCH="$(PREPARE_MATCH_NOSPACE(random_key=abc))" +MATCH="$(PREPARE_MATCH_NOSPACE(abc))" AT_CHECK_UNQUOTED([ovs-vsctl-bashcomp.bash test "add Bridge br0 other_config random_key=abc"], [0], [dnl ${MATCH} @@ -638,14 +638,14 @@ AT_CHECK_UNQUOTED([ovs-vsctl-bashcomp.bash test "set Bridge br0 other"], ${MATCH} ]) # then, with the ':' we should complete on key. -TMP="$(ovs-vsctl --no-heading --columns=other_config list Bridge br0 | tr -d '{\"}' | tr -s ', ' '\n' | cut -d'=' -f1 | xargs printf "other_config:%s\n")" +TMP="$(ovs-vsctl --no-heading --columns=other_config list Bridge br0 | tr -d '{\"}' | tr -s ', ' '\n' | cut -d'=' -f1)" MATCH="$(PREPARE_MATCH_NOSPACE(${TMP}))" AT_CHECK_UNQUOTED([ovs-vsctl-bashcomp.bash test "set Bridge br0 other_config:"], [0], [dnl ${MATCH} ]) # finally, if user fill in some value, we should just complete on user input. -MATCH="$(PREPARE_MATCH_NOSPACE(other_config:random_val1=12345))" +MATCH="$(PREPARE_MATCH_NOSPACE(random_val1))" AT_CHECK_UNQUOTED([ovs-vsctl-bashcomp.bash test "set Bridge br0 other_config:random_val1=12345"], [0], [dnl ${MATCH} @@ -677,14 +677,14 @@ AT_CHECK_UNQUOTED([ovs-vsctl-bashcomp.bash test "set-manager "], ${MATCH} ]) # filename completion on unix, punix. -MATCH="$(PREPARE_MATCH_NOSPACE(unix:testsuite.log))" +MATCH="$(PREPARE_MATCH_NOSPACE(testsuite.log))" AT_CHECK_UNQUOTED([ovs-vsctl-bashcomp.bash test "set-manager unix:test"], [0], [dnl ${MATCH} ]) # no completion on other type, just return available types. # in real environment, bash will not complete on anything. -MATCH="$(PREPARE_MATCH_NOSPACE(pssl: ptcp: punix: ssl: tcp: unix:))" +MATCH="$(PREPARE_MATCH_NOSPACE(pssl: ptcp: punix: tcp: unix:))" AT_CHECK_UNQUOTED([ovs-vsctl-bashcomp.bash test "set-manager ssl:something"], [0], [dnl ${MATCH} diff --git a/utilities/ovs-vsctl-bashcomp.bash b/utilities/ovs-vsctl-bashcomp.bash index e79c6a217..a3273f8ee 100755 --- a/utilities/ovs-vsctl-bashcomp.bash +++ b/utilities/ovs-vsctl-bashcomp.bash @@ -202,7 +202,7 @@ _ovs_vsctl_complete_key_given_table_column () { keys=$(_ovs_vsctl --no-heading --columns="$3" list \ "$2" \ | tr -d '{\"}' | tr -s ', ' '\n' | cut -d'=' -f1 \ - | xargs printf "$4%s\n" | _ovs_vsctl_check_startswith_string "$1") + | xargs printf "$4%s\n" | _ovs_vsctl_check_startswith_string "$4$1") result="${keys}" printf -- "%s\n" "${result}" } @@ -604,6 +604,43 @@ _ovs_vsctl_process_messages () { fi } +# colon, equal sign will mess up the completion output, just +# removes the colon-word and equal-word prefix from COMPREPLY items. +# +# Implementation of this function refers to the __ltrim_colon_completions +# function defined in bash_completion module. +# +# $1: Current argument +# $2: $COMP_WORDBREAKS +# $3: ${COMPREPLY[@]} +_ovs_vsctl_trim_compreply() { + local cur comp_wordbreaks + local compreply + + cur=$1 && shift + comp_wordbreaks=$1 && shift + compreply=( $@ ) + + if [[ "$cur" == *:* && "$comp_wordbreaks" == *:* ]]; then + local colon_word=${cur%${cur##*:}} + local i=${#compreply[*]} + cur=${cur##*:} + while [ $((--i)) -ge 0 ]; do + compreply[$i]=${compreply[$i]#"$colon_word"} + done + fi + + if [[ "$cur" == *=* && "$comp_wordbreaks" == *=* ]]; then + local equal_word=${cur%${cur##*=}} + local i=${#compreply[*]} + while [ $((--i)) -ge 0 ]; do + compreply[$i]=${compreply[$i]#"$equal_word"} + done + fi + + printf "%s " "${compreply[@]}" +} + # The general strategy here is that the same functions that decide # completions can also capture the necessary context for later # completions. This means that there is no distinction between the @@ -627,7 +664,7 @@ _ovs_vsctl_process_messages () { # status of the function _ovs_vsctl_complete_argument represents where # it has determined that the next argument will be. _ovs_vsctl_bashcomp () { - local cur valid_globals cmd_args raw_cmd cmd_pos valid_globals valid_opts + local words cword valid_globals cmd_args raw_cmd cmd_pos valid_globals valid_opts local test="false" # Does not support BASH_VERSION < 4.0 @@ -645,6 +682,12 @@ _ovs_vsctl_bashcomp () { <<< "$tmp" export COMP_WORDS export COMP_CWORD="$((${#COMP_WORDS[@]}-1))" + else + # If not in test mode, reassembles the COMP_WORDS and COMP_CWORD + # using just space as word break. + _get_comp_words_by_ref -n "\"'><=;|&(:" -w words -i cword + COMP_WORDS=( "${words[@]}" ) + COMP_CWORD=${cword} fi # Extract the conf.db path. @@ -654,20 +697,18 @@ _ovs_vsctl_bashcomp () { fi # If having trouble accessing the database, return. - if ! _ovs_vsctl get-manager 2>/dev/null; then + if ! _ovs_vsctl get-manager 1>/dev/null 2>/dev/null; then return 1; fi _OVS_VSCTL_PARSED_ARGS=() _OVS_VSCTL_NEW_RECORDS=() cmd_pos=-1 - cur=${COMP_WORDS[COMP_CWORD]} valid_globals=true valid_opts=true valid_commands=true given_opts="" index=1 - export COMP_WORDBREAKS=" " for word in "${COMP_WORDS[@]:1:${COMP_CWORD}} "; do _OVS_VSCTL_COMP_NOSPACE=false local completion @@ -753,6 +794,8 @@ _ovs_vsctl_bashcomp () { completion="$(sort -u <<< "$(tr ' ' '\n' <<< ${completion})")" if [ $index -eq $COMP_CWORD ]; then if [ "$test" = "true" ]; then + completion="$(_ovs_vsctl_trim_compreply "$word" ":=" ${completion} | \ + tr ' ' '\n')" if [ "${_OVS_VSCTL_COMP_NOSPACE}" = "true" ]; then printf "%s" "$completion" | sed -e '/^$/d' else @@ -767,6 +810,8 @@ _ovs_vsctl_bashcomp () { compopt +o nospace COMPREPLY=( $(compgen -W "${completion}" -- $word) ) fi + COMPREPLY=( $(_ovs_vsctl_trim_compreply "$word" \ + "${COMP_WORDBREAKS}" ${COMPREPLY[@]}) ) fi fi index=$(($index+1)) -- cgit v1.2.1 From 2c9907cde3be90e12efb3c2729c0a8e98e898a2d Mon Sep 17 00:00:00 2001 From: Alex Wang Date: Wed, 18 Mar 2015 14:32:23 -0700 Subject: bashcomp: Install and package completion scripts. This commit makes the bash completion scripts be installed to $(sysconfdir)/bash_completion.d/ through 'make install' and to /etc/bash_completion.d/ through package installation. This will make the scripts available for each bash session. An alternative is to put scripts to /usr/share/bash_completion/ directory. However, this is not supported by earlier version of bash completion. Signed-off-by: Alex Wang --- Makefile.am | 2 ++ debian/openvswitch-common.install | 1 + debian/openvswitch-switch.install | 1 + rhel/openvswitch.spec.in | 2 ++ utilities/automake.mk | 4 ++++ utilities/ovs-command-bashcomp.INSTALL.md | 13 ++++++++++--- xenserver/openvswitch-xen.spec.in | 2 ++ 7 files changed, 22 insertions(+), 3 deletions(-) diff --git a/Makefile.am b/Makefile.am index e1a4e1780..ab2216749 100644 --- a/Makefile.am +++ b/Makefile.am @@ -137,6 +137,7 @@ OVSIDL_BUILT = pkgdata_DATA = sbin_SCRIPTS = scripts_SCRIPTS = +completion_SCRIPTS = scripts_DATA = SUFFIXES = check_DATA = @@ -144,6 +145,7 @@ check_SCRIPTS = pkgconfig_DATA = scriptsdir = $(pkgdatadir)/scripts +completiondir = $(sysconfdir)/bash_completion.d pkgconfigdir = $(libdir)/pkgconfig # This ensures that files added to EXTRA_DIST are always distributed, diff --git a/debian/openvswitch-common.install b/debian/openvswitch-common.install index 11bb59670..f0841529a 100644 --- a/debian/openvswitch-common.install +++ b/debian/openvswitch-common.install @@ -1,3 +1,4 @@ +etc/bash_completion.d/ovs-appctl-bashcomp.bash usr/bin/ovs-appctl usr/bin/ovs-benchmark usr/bin/ovs-docker diff --git a/debian/openvswitch-switch.install b/debian/openvswitch-switch.install index c4f1426fe..b5d006321 100644 --- a/debian/openvswitch-switch.install +++ b/debian/openvswitch-switch.install @@ -1,3 +1,4 @@ +etc/bash_completion.d/ovs-vsctl-bashcomp.bash usr/bin/ovs-dpctl usr/bin/ovs-dpctl-top usr/bin/ovs-pcap diff --git a/rhel/openvswitch.spec.in b/rhel/openvswitch.spec.in index 56603ccbb..1ea685d3b 100644 --- a/rhel/openvswitch.spec.in +++ b/rhel/openvswitch.spec.in @@ -123,6 +123,8 @@ exit 0 %files %defattr(-,root,root) +/etc/bash_completion.d/ovs-appctl-bashcomp.bash +/etc/bash_completion.d/ovs-vsctl-bashcomp.bash /etc/init.d/openvswitch %config(noreplace) /etc/logrotate.d/openvswitch /etc/sysconfig/network-scripts/ifup-ovs diff --git a/utilities/automake.mk b/utilities/automake.mk index 8b55e2d5d..a06630f1f 100644 --- a/utilities/automake.mk +++ b/utilities/automake.mk @@ -22,6 +22,10 @@ scripts_SCRIPTS += \ utilities/ovs-save scripts_DATA += utilities/ovs-lib +completion_SCRIPTS += \ + utilities/ovs-appctl-bashcomp.bash \ + utilities/ovs-vsctl-bashcomp.bash + check_SCRIPTS += \ utilities/ovs-appctl-bashcomp.bash \ utilities/ovs-vsctl-bashcomp.bash diff --git a/utilities/ovs-command-bashcomp.INSTALL.md b/utilities/ovs-command-bashcomp.INSTALL.md index 411f42fe6..9bdef40f3 100644 --- a/utilities/ovs-command-bashcomp.INSTALL.md +++ b/utilities/ovs-command-bashcomp.INSTALL.md @@ -65,9 +65,16 @@ ovs-vsctl-bashcomp How to use: ----------- - To use the scripts, either copy them inside /etc/bash_completion.d/ or - manually run it directly in bash via . ovs-appctl-bashcomp.bash or - . ovs-vsctl-bashcomp.bash. + The bashcomp scripts should be placed at /etc/bash_completion.d/ + to be available for all bash sessions. Running 'make install' + will place the scripts to $(sysconfdir)/bash_completion.d/. So user + should specify --sysconfdir=/etc at configuration. Meanwhile, if OVS is + installed from packages, the scripts will automatically be placed inside + /etc/bash_completion.d/. + + If you just want to run the scripts in one bash, you can remove them from + /etc/bash_completion.d/ and run the scripts via '. ovs-appctl-bashcomp.bash' + or '. ovs-vsctl-bashcomp.bash'. Test: ----- diff --git a/xenserver/openvswitch-xen.spec.in b/xenserver/openvswitch-xen.spec.in index 3bae86a51..4d98d2e01 100644 --- a/xenserver/openvswitch-xen.spec.in +++ b/xenserver/openvswitch-xen.spec.in @@ -430,6 +430,8 @@ exit 0 %files %defattr(-,root,root) +/etc/bash_completion.d/ovs-appctl-bashcomp.bash +/etc/bash_completion.d/ovs-vsctl-bashcomp.bash /etc/init.d/openvswitch /etc/init.d/openvswitch-xapi-update /etc/xapi.d/plugins/openvswitch-cfg-update -- cgit v1.2.1 From 5568661cbff1095b595c6020f2a311d8743dc47f Mon Sep 17 00:00:00 2001 From: Russell Bryant Date: Mon, 23 Mar 2015 13:49:10 -0400 Subject: INSTALL.DPDK.md: Terminate code section. Add a missing terminator for a code section. Without this, the rendering on github at least shows the rest of the file as a code block. Signed-off-by: Russell Bryant Signed-off-by: Ben Pfaff --- INSTALL.DPDK.md | 1 + 1 file changed, 1 insertion(+) diff --git a/INSTALL.DPDK.md b/INSTALL.DPDK.md index 5b6127233..60889d01d 100644 --- a/INSTALL.DPDK.md +++ b/INSTALL.DPDK.md @@ -430,6 +430,7 @@ qemu-wrap.py -cpu host -boot c -hda -m 4096 -smp 4 --enable-kvm -nographic -vnc none -net none -netdev tap,id=net1, script=no,downscript=no,ifname=if1,vhost=on -device virtio-net-pci, netdev=net1,mac=00:00:00:00:00:01 +``` DPDK vhost VM configuration with libvirt: ----------------------------------------- -- cgit v1.2.1 From 14691214d171d0209ec6e96717f89550a3d3119b Mon Sep 17 00:00:00 2001 From: Dennis Flynn Date: Wed, 18 Mar 2015 14:47:14 -0400 Subject: auto-attach: Support latest version of auto-attach LLDP TLVs The following enhancements to the auto-attach feature are provided - Support recent modifications to the AA element discovery TLV - Support recent Avaya Organizationally Unique ID (OUI) change. (This will change to IEEE assigned OUI once AA standard has been ratified) - Remove some Avaya specific #defines The primary purpose of this commit is to catch up with the latest changes made to the auto attach TLVs as the Auto Attach feature progresses through the 802.1Q IEEE standards committee. Most notably this includes some minor rework of the AA element discovery TLV and a recent change to the Avaya OUI value. Signed-off-by: Dennis Flynn Signed-off-by: Ben Pfaff --- lib/lldp/aa-structs.h | 6 ++- lib/lldp/lldp-tlv.h | 30 ++++++++---- lib/lldp/lldp.c | 127 +++++++++++++++++++++++++++++++++----------------- lib/ovs-lldp.c | 17 ++++--- tests/test-aa.c | 33 ++++++------- 5 files changed, 133 insertions(+), 80 deletions(-) diff --git a/lib/lldp/aa-structs.h b/lib/lldp/aa-structs.h index 567a831af..983c74c31 100644 --- a/lib/lldp/aa-structs.h +++ b/lib/lldp/aa-structs.h @@ -26,12 +26,14 @@ struct lldp_aa_element_system_id { uint8_t system_mac[6]; uint16_t conn_type; - uint16_t smlt_id; - uint8_t mlt_id[2]; + uint16_t rsvd; + uint8_t rsvd2[2]; }; struct lldpd_aa_element_tlv { uint16_t type; + uint16_t vlan_tagging; + uint16_t auto_prov_mode; uint16_t mgmt_vlan; struct lldp_aa_element_system_id system_id; }; diff --git a/lib/lldp/lldp-tlv.h b/lib/lldp/lldp-tlv.h index 237414d5a..2b948281f 100644 --- a/lib/lldp/lldp-tlv.h +++ b/lib/lldp/lldp-tlv.h @@ -36,7 +36,7 @@ #define LLDP_TLV_ORG_DOT1 {0x00, 0x80, 0xc2} #define LLDP_TLV_ORG_DOT3 {0x00, 0x12, 0x0f} #define LLDP_TLV_ORG_MED {0x00, 0x12, 0xbb} -#define LLDP_TLV_ORG_AVAYA {0x00, 0x40, 0x0D} +#define LLDP_TLV_ORG_AVAYA {0x00, 0x04, 0x0D} #define LLDP_TLV_ORG_DCBX {0x00, 0x1b, 0x21} #define LLDP_TLV_DOT1_PVID 1 @@ -61,16 +61,26 @@ #define LLDP_TLV_MED_IV_MODEL 10 #define LLDP_TLV_MED_IV_ASSET 11 -#define LLDP_TLV_AA_ELEMENT_SUBTYPE 0x08 -#define LLDP_TLV_AA_ISID_VLAN_ASGNS_SUBTYPE 0x09 +#define LLDP_TLV_AA_ELEMENT_SUBTYPE 0x0b +#define LLDP_TLV_AA_ISID_VLAN_ASGNS_SUBTYPE 0x0c #define LLDP_TLV_AA_ISID_VLAN_DIGEST_LENGTH 32 -#define LLDP_TLV_AA_ELEM_TYPE_UNKNOWN 1 -#define LLDP_TLV_AA_ELEM_TYPE_SERVER 2 -#define LLDP_TLV_AA_ELEM_TYPE_PROXY 3 -#define LLDP_TLV_AA_ELEM_TYPE_UNTAG_CLIENT 4 -#define LLDP_TLV_AA_ELEM_TYPE_TAG_CLIENT 5 -#define LLDP_TLV_AA_ELEM_TYPE_SERV_NO_AUTH 6 -#define LLDP_TLV_AA_ELEM_TYPE_PROXY_NO_AUTH 7 + +#define LLDP_TLV_AA_ELEM_TYPE_UNKNOWN 1 +#define LLDP_TLV_AA_ELEM_TYPE_SERVER 2 +#define LLDP_TLV_AA_ELEM_TYPE_PROXY 3 +#define LLDP_TLV_AA_ELEM_TYPE_SERV_NO_AUTH 4 +#define LLDP_TLV_AA_ELEM_TYPE_PROXY_NO_AUTH 5 +#define LLDP_TLV_AA_ELEM_TYPE_CLIENT_WIRELESS_ACCESS_POINT_TYPE1 6 +#define LLDP_TLV_AA_ELEM_TYPE_CLIENT_WIRELESS_ACCESS_POINT_TYPE2 7 +#define LLDP_TLV_AA_ELEM_TYPE_CLIENT_SWITCH 8 +#define LLDP_TLV_AA_ELEM_TYPE_CLIENT_ROUTER 9 +#define LLDP_TLV_AA_ELEM_TYPE_CLIENT_IP_PHONE 10 +#define LLDP_TLV_AA_ELEM_TYPE_CLIENT_IP_CAMERA 11 +#define LLDP_TLV_AA_ELEM_TYPE_CLIENT_IP_VIDEO 12 +#define LLDP_TLV_AA_ELEM_TYPE_CLIENT_SECURITY_DEVICE 13 +#define LLDP_TLV_AA_ELEM_TYPE_CLIENT_VIRTUAL_SWITCH 14 +#define LLDP_TLV_AA_ELEM_TYPE_CLIENT_SERVER_ENDPOINT 15 + #define LLDP_TLV_AA_ELEM_CONN_TYPE_SINGLE 0 #define LLDP_TLV_AA_ELEM_CONN_TYPE_MLT 1 #define LLDP_TLV_AA_ELEM_CONN_TYPE_SLT 2 diff --git a/lib/lldp/lldp.c b/lib/lldp/lldp.c index d77bcd082..493c2ffa9 100644 --- a/lib/lldp/lldp.c +++ b/lib/lldp/lldp.c @@ -235,53 +235,69 @@ lldp_send(struct lldpd *global OVS_UNUSED, lldp_tlv_end(p, start); } - /* Add Auto Attach tlvs to packet */ + /* Add Auto Attach tlvs V3.1 to packet. LLDP FA element v3.1 format: + TLV Type[127] TLV Length[50 octets] Avaya OUI[00-04-0D] Subtype[11] + 7 bits 9 bits 3 octets 1 octet + HMAC-SHA Digest Element Type State Mgmt VLAN Rsvd System ID + 32 octets 6 bits 6 bits 12 bits 1 octet 10 octets + */ /* AA-ELEMENT */ if (port->p_element.type != 0) { - u_int8_t aa_element_first_byte; - u_int8_t aa_element_second_byte = 0; + u_int16_t aa_element_first_word = 0; + u_int16_t aa_element_second_word = 0; + u_int16_t aa_element_state = 0; u_int8_t aa_elem_sys_id_first_byte; u_int8_t aa_elem_sys_id_second_byte; - /* Element type should be first 4 most significant bits, so bitwise OR - * that with the first 4 bits of the 12-bit-wide mgmt_vlan - */ - aa_element_first_byte = (((port->p_element.type & 0xF) << 4) | - ((port->p_element.mgmt_vlan >> 8) & 0xF)); - - /* Second byte should just be the remaining 8 bits of .mgmt_vlan */ - aa_element_second_byte = port->p_element.mgmt_vlan & 0x0FF; - - /* .conn_type should be 4 most sig. bits, so bitwise OR that - * with the first 4 bits of the 12-bit-wide .smlt_id - */ + /* Link VLAN Tagging Requirements (bit 1), + * Automatic Provisioning Mode (bit 2/3) (left to right, 1 based) */ + aa_element_state = ((port->p_element.vlan_tagging & 0x1) << 5) | + ((port->p_element.auto_prov_mode & 0x3) << 3); + + /* Element first word should be first 6 most significant bits of + * element type, bitwise OR that with the next 6 bits of the state, + * bitwise OR with the first 4 bits of mgmt vlan id. + * Element type should be LLDP_TLV_AA_ELEM_TYPE_VIRTUAL_SWITCH for + * AA client */ + aa_element_first_word = (port->p_element.type << 10) | + (aa_element_state << 4) | + ((port->p_element.mgmt_vlan & 0x0F00)>> 8); + + /* Element second type should be the first 8 most significant bits + * of the remaining 8 bits of mgmt vlan id. */ + aa_element_second_word = (port->p_element.mgmt_vlan & 0xFF) << 8; + + /* System id first byte should be first 3 most significant bits of + * connecion type, bitwise OR that with the device state and bitwise + * OR that with the first 2 most significant bitsof rsvd (10 bits). */ aa_elem_sys_id_first_byte = - ((port->p_element.system_id.conn_type & 0xF) << 4) | - ((port->p_element.system_id.smlt_id >> 8) & 0xF); + ((port->p_element.system_id.conn_type & 0x7) << 5) | + ((port->p_element.system_id.rsvd >> 8) & 0x3); - /* Second byte should just be the remaining 8 bits of .smlt_id */ - aa_elem_sys_id_second_byte = port->p_element.system_id.smlt_id & 0x0FF; + /* Second byte should just be the remaining 8 bits of 10 bits rsvd */ + aa_elem_sys_id_second_byte = + (port->p_element.system_id.rsvd & 0xFF); + + memset(msg_auth_digest, 0, sizeof msg_auth_digest); lldp_tlv_start(p, LLDP_TLV_ORG, &start); dp_packet_put(p, avaya, sizeof avaya); lldp_tlv_put_u8(p, LLDP_TLV_AA_ELEMENT_SUBTYPE); - lldp_tlv_put_u8(p, aa_element_first_byte); - lldp_tlv_put_u8(p, aa_element_second_byte); + dp_packet_put(p, msg_auth_digest, sizeof msg_auth_digest); + lldp_tlv_put_u16(p, aa_element_first_word); + lldp_tlv_put_u16(p, aa_element_second_word); dp_packet_put(p, &port->p_element.system_id.system_mac, sizeof port->p_element.system_id.system_mac); lldp_tlv_put_u8(p, aa_elem_sys_id_first_byte); lldp_tlv_put_u8(p, aa_elem_sys_id_second_byte); - dp_packet_put(p, &port->p_element.system_id.mlt_id, - sizeof port->p_element.system_id.mlt_id); + dp_packet_put(p, &port->p_element.system_id.rsvd2, + sizeof port->p_element.system_id.rsvd2); lldp_tlv_end(p, start); } if (!list_is_empty(&port->p_isid_vlan_maps)) { - int j; - for (j = 0; j < LLDP_TLV_AA_ISID_VLAN_DIGEST_LENGTH; j++) { - msg_auth_digest[j] = 0; - } + memset(msg_auth_digest, 0, sizeof msg_auth_digest); lldp_tlv_start(p, LLDP_TLV_ORG, &start); dp_packet_put(p, avaya, sizeof avaya); @@ -314,6 +330,7 @@ lldp_send(struct lldpd *global OVS_UNUSED, if (!hardware->h_lport.p_lastframe || hardware->h_lport.p_lastframe->size != lldp_len || memcmp(hardware->h_lport.p_lastframe->frame, lldp, lldp_len)) { + struct lldpd_frame *frame = xmalloc(sizeof *frame + lldp_len); frame->size = lldp_len; memcpy(frame->frame, lldp, lldp_len); @@ -327,8 +344,8 @@ lldp_send(struct lldpd *global OVS_UNUSED, int lldp_decode(struct lldpd *cfg OVS_UNUSED, char *frame, int s, - struct lldpd_hardware *hardware, struct lldpd_chassis **newchassis, - struct lldpd_port **newport) + struct lldpd_hardware *hardware, struct lldpd_chassis **newchassis, + struct lldpd_port **newport) { struct lldpd_chassis *chassis; struct lldpd_port *port; @@ -372,6 +389,7 @@ lldp_decode(struct lldpd *cfg OVS_UNUSED, char *frame, int s, "received on %s", hardware->h_ifname); goto malformed; } + PEEK_DISCARD(ETH_ADDR_LEN); /* Skip source address */ if (PEEK_UINT16 != ETHERTYPE_LLDP) { VLOG_INFO("non LLDP frame received on %s", hardware->h_ifname); @@ -498,34 +516,57 @@ lldp_decode(struct lldpd *cfg OVS_UNUSED, char *frame, int s, /* LLDP-MED */ hardware->h_rx_unrecognized_cnt++; } else if (memcmp(avaya_oid, orgid, sizeof orgid) == 0) { - u_int16_t aa_element_word; - u_int16_t aa_status_vlan_word; + u_int32_t aa_element_dword; u_int16_t aa_system_id_word; + u_int16_t aa_status_vlan_word; + u_int8_t aa_element_state; unsigned short num_mappings; switch(tlv_subtype) { case LLDP_TLV_AA_ELEMENT_SUBTYPE: - aa_element_word = PEEK_UINT16; + PEEK_BYTES(&msg_auth_digest, sizeof msg_auth_digest); + + aa_element_dword = PEEK_UINT32; + + /* Type is first 6 most-significant bits of + * aa_element_dword */ + port->p_element.type = aa_element_dword >> 26; - /* Type is first 4 most-significant bits */ - port->p_element.type = aa_element_word >> 12; + /* State is 6 most significant bits of aa_element_dword */ + aa_element_state = (aa_element_dword >> 20) & 0x3F; - /* mgmt_vlan is last 12 bits */ - port->p_element.mgmt_vlan = aa_element_word & 0x0FFF; - VLOG_INFO("Element type: %X, Mgmt vlan: %X", + /* vlan tagging requirement is the bit 1(left to right) + * of the 6 bits state (1 based) */ + port->p_element.vlan_tagging = + (aa_element_state >> 5) & 0x1; + + /* Automatic provision mode is the bit 2/3(left to right) + * of the 6 bits state (1 based) */ + port->p_element.auto_prov_mode = + (aa_element_state >> 3) & 0x3; + + /* mgmt_vlan is the 12 bits of aa_element_dword from + * bit 12 */ + port->p_element.mgmt_vlan = + (aa_element_dword >> 8) & 0xFFF; + VLOG_INFO("Element type: %X, vlan tagging %X, " + "auto prov mode %x, Mgmt vlan: %X", port->p_element.type, + port->p_element.vlan_tagging, + port->p_element.auto_prov_mode, port->p_element.mgmt_vlan); + PEEK_BYTES(&port->p_element.system_id.system_mac, sizeof port->p_element.system_id.system_mac); VLOG_INFO("System mac: "ETH_ADDR_FMT, - ETH_ADDR_ARGS(port->p_element.system_id.system_mac)); + ETH_ADDR_ARGS(port->p_element.system_id.system_mac)); aa_system_id_word = PEEK_UINT16; port->p_element.system_id.conn_type = - aa_system_id_word >> 12; - port->p_element.system_id.smlt_id = - aa_system_id_word & 0x0FFF; - PEEK_BYTES(&port->p_element.system_id.mlt_id, - sizeof port->p_element.system_id.mlt_id); + aa_system_id_word >> 13; + port->p_element.system_id.rsvd = aa_system_id_word & + 0x03FF; + PEEK_BYTES(&port->p_element.system_id.rsvd2, + sizeof port->p_element.system_id.rsvd2); break; case LLDP_TLV_AA_ISID_VLAN_ASGNS_SUBTYPE: diff --git a/lib/ovs-lldp.c b/lib/ovs-lldp.c index a30eca59a..db97648e6 100644 --- a/lib/ovs-lldp.c +++ b/lib/ovs-lldp.c @@ -822,16 +822,15 @@ lldp_create(const struct netdev *netdev, hw->h_lport.p_id_len = strlen(netdev_get_name(netdev)); /* Auto Attach element tlv */ - hw->h_lport.p_element.type = LLDP_TLV_AA_ELEM_TYPE_TAG_CLIENT; + hw->h_lport.p_element.type = LLDP_TLV_AA_ELEM_TYPE_CLIENT_VIRTUAL_SWITCH; hw->h_lport.p_element.mgmt_vlan = 0; memcpy(&hw->h_lport.p_element.system_id.system_mac, lchassis->c_id, lchassis->c_id_len); hw->h_lport.p_element.system_id.conn_type = LLDP_TLV_AA_ELEM_CONN_TYPE_SINGLE; - - hw->h_lport.p_element.system_id.smlt_id = 0; - hw->h_lport.p_element.system_id.mlt_id[0] = 0; - hw->h_lport.p_element.system_id.mlt_id[1] = 0; + hw->h_lport.p_element.system_id.rsvd = 0; + hw->h_lport.p_element.system_id.rsvd2[0] = 0; + hw->h_lport.p_element.system_id.rsvd2[1] = 0; list_init(&hw->h_lport.p_isid_vlan_maps); list_init(&lldp->lldpd->g_hardware); @@ -908,15 +907,15 @@ lldp_create_dummy(void) hw->h_lport.p_id_len = strlen(hw->h_lport.p_id); /* Auto Attach element tlv */ - hw->h_lport.p_element.type = LLDP_TLV_AA_ELEM_TYPE_TAG_CLIENT; + hw->h_lport.p_element.type = LLDP_TLV_AA_ELEM_TYPE_CLIENT_VIRTUAL_SWITCH; hw->h_lport.p_element.mgmt_vlan = 0; memcpy(&hw->h_lport.p_element.system_id.system_mac, lchassis->c_id, lchassis->c_id_len); hw->h_lport.p_element.system_id.conn_type = LLDP_TLV_AA_ELEM_CONN_TYPE_SINGLE; - hw->h_lport.p_element.system_id.smlt_id = 0; - hw->h_lport.p_element.system_id.mlt_id[0] = 0; - hw->h_lport.p_element.system_id.mlt_id[1] = 0; + hw->h_lport.p_element.system_id.rsvd = 0; + hw->h_lport.p_element.system_id.rsvd2[0] = 0; + hw->h_lport.p_element.system_id.rsvd2[1] = 0; list_init(&hw->h_lport.p_isid_vlan_maps); list_init(&lldp->lldpd->g_hardware); diff --git a/tests/test-aa.c b/tests/test-aa.c index 4fb26188f..9dabce16d 100644 --- a/tests/test-aa.c +++ b/tests/test-aa.c @@ -98,12 +98,12 @@ check_received_aa(struct lldpd_port *sport, sport->p_element.system_id.system_mac[5]); assert(rport->p_element.system_id.conn_type == sport->p_element.system_id.conn_type); - assert(rport->p_element.system_id.smlt_id == - sport->p_element.system_id.smlt_id); - assert(rport->p_element.system_id.mlt_id[0] == - sport->p_element.system_id.mlt_id[0]); - assert(rport->p_element.system_id.mlt_id[1] == - sport->p_element.system_id.mlt_id[1]); + assert(rport->p_element.system_id.rsvd == + sport->p_element.system_id.rsvd); + assert(rport->p_element.system_id.rsvd2[0] == + sport->p_element.system_id.rsvd2[0]); + assert(rport->p_element.system_id.rsvd2[1] == + sport->p_element.system_id.rsvd2[1]); /* Should receive 2 mappings */ assert(!list_is_empty(&rport->p_isid_vlan_maps)); @@ -160,7 +160,8 @@ test_aa_send(void) hardware.h_lport.p_mfs = 1516; /* Auto attach element discovery info */ - hardware.h_lport.p_element.type = LLDP_TLV_AA_ELEM_TYPE_TAG_CLIENT; + hardware.h_lport.p_element.type = + LLDP_TLV_AA_ELEM_TYPE_CLIENT_VIRTUAL_SWITCH; hardware.h_lport.p_element.mgmt_vlan = 0xCDC; hardware.h_lport.p_element.system_id.system_mac[0] = 0x1; hardware.h_lport.p_element.system_id.system_mac[1] = 0x2; @@ -170,9 +171,9 @@ test_aa_send(void) hardware.h_lport.p_element.system_id.system_mac[5] = 0x6; hardware.h_lport.p_element.system_id.conn_type = 0x5; - hardware.h_lport.p_element.system_id.smlt_id = 0x3CC; - hardware.h_lport.p_element.system_id.mlt_id[0] = 0xB; - hardware.h_lport.p_element.system_id.mlt_id[1] = 0xE; + hardware.h_lport.p_element.system_id.rsvd = 0x3CC; + hardware.h_lport.p_element.system_id.rsvd2[0] = 0xB; + hardware.h_lport.p_element.system_id.rsvd2[1] = 0xE; /* Local chassis info */ chassis.c_id_subtype = LLDP_CHASSISID_SUBTYPE_LLADDR; @@ -242,12 +243,12 @@ test_aa_send(void) hw->h_lport.p_element.system_id.conn_type = hardware.h_lport.p_element.system_id.conn_type; - hw->h_lport.p_element.system_id.smlt_id = - hardware.h_lport.p_element.system_id.smlt_id; - hw->h_lport.p_element.system_id.mlt_id[0] = - hardware.h_lport.p_element.system_id.mlt_id[0]; - hw->h_lport.p_element.system_id.mlt_id[1] = - hardware.h_lport.p_element.system_id.mlt_id[1]; + hw->h_lport.p_element.system_id.rsvd = + hardware.h_lport.p_element.system_id.rsvd; + hw->h_lport.p_element.system_id.rsvd2[0] = + hardware.h_lport.p_element.system_id.rsvd2[0]; + hw->h_lport.p_element.system_id.rsvd2[1] = + hardware.h_lport.p_element.system_id.rsvd2[1]; /* Populate instance with two auto attach isid/vlan mappings */ map[0].isid_vlan_data.status = map_init[0].isid_vlan_data.status; -- cgit v1.2.1 From 677d9158fc0aa16f875198d83c7bd8f87238aed5 Mon Sep 17 00:00:00 2001 From: Jonathan Vestin Date: Wed, 18 Mar 2015 17:13:01 +0100 Subject: netdev-linux: Support for SFQ, FQ_CoDel and CoDel qdiscs. This patch adds support for SFQ, CoDel and FQ_CoDel classless qdiscs to Open vSwitch. It also removes the requirement for a QoS to have at least one Queue (as this makes no sense when using classless qdiscs). I have also not implemented class_{get,set,delete,get_stats,dump_stats} because they are meant for qdiscs with classes. Signed-off-by: Jonathan Vestin [blp@nicira.com mostly applied stylistic changes] Signed-off-by: Ben Pfaff --- AUTHORS | 2 +- NEWS | 1 + lib/netdev-linux.c | 643 +++++++++++++++++++++++++++++++++++++++++++++++++++ vswitchd/bridge.c | 2 +- vswitchd/vswitch.xml | 27 +++ 5 files changed, 673 insertions(+), 2 deletions(-) diff --git a/AUTHORS b/AUTHORS index db4520f37..8fba915f5 100644 --- a/AUTHORS +++ b/AUTHORS @@ -85,6 +85,7 @@ Jesse Gross jesse@nicira.com Jing Ai jinga@google.com Joe Perches joe@perches.com Joe Stringer joestringer@nicira.com +Jonathan Vestin jonavest@kau.se Jun Nakajima jun.nakajima@intel.com Justin Pettit jpettit@nicira.com Keith Amidon keith@nicira.com @@ -268,7 +269,6 @@ Joan Cirer joan@ev0.net John Darrington john@darrington.wattle.id.au John Galgay john@galgay.net John Hurley john.hurley@netronome.com -Jonathan Vestin jonavest@kau.se K 華 k940545@hotmail.com Kevin Mancuso kevin.mancuso@rackspace.com Kiran Shanbhog kiran@vmware.com diff --git a/NEWS b/NEWS index 9461f536d..79b3703d6 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,6 @@ Post-v2.3.0 --------------------- + - Added support for SFQ, FQ_CoDel and CoDel qdiscs. - Add bash command-line completion support for ovs-vsctl Please check utilities/ovs-command-compgen.INSTALL.md for how to use. - The MAC learning feature now includes per-port fairness to mitigate diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index 9b2e74f7e..8253dfb4b 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -377,12 +377,18 @@ tc_destroy(struct tc *tc) static const struct tc_ops tc_ops_htb; static const struct tc_ops tc_ops_hfsc; +static const struct tc_ops tc_ops_codel; +static const struct tc_ops tc_ops_fqcodel; +static const struct tc_ops tc_ops_sfq; static const struct tc_ops tc_ops_default; static const struct tc_ops tc_ops_other; static const struct tc_ops *const tcs[] = { &tc_ops_htb, /* Hierarchy token bucket (see tc-htb(8)). */ &tc_ops_hfsc, /* Hierarchical fair service curve. */ + &tc_ops_codel, /* Controlled delay */ + &tc_ops_fqcodel, /* Fair queue controlled delay */ + &tc_ops_sfq, /* Stochastic fair queueing */ &tc_ops_default, /* Default qdisc (see tc-pfifo_fast(8)). */ &tc_ops_other, /* Some other qdisc. */ NULL @@ -2832,6 +2838,643 @@ const struct netdev_class netdev_internal_class = NULL, /* get_features */ netdev_internal_get_status); + +#define CODEL_N_QUEUES 0x0000 + +struct codel { + struct tc tc; + uint32_t target; + uint32_t limit; + uint32_t interval; +}; + +static struct codel * +codel_get__(const struct netdev *netdev_) +{ + struct netdev_linux *netdev = netdev_linux_cast(netdev_); + return CONTAINER_OF(netdev->tc, struct codel, tc); +} + +static void +codel_install__(struct netdev *netdev_, uint32_t target, uint32_t limit, + uint32_t interval) +{ + struct netdev_linux *netdev = netdev_linux_cast(netdev_); + struct codel *codel; + + codel = xmalloc(sizeof *codel); + tc_init(&codel->tc, &tc_ops_codel); + codel->target = target; + codel->limit = limit; + codel->interval = interval; + + netdev->tc = &codel->tc; +} + +static int +codel_setup_qdisc__(struct netdev *netdev, uint32_t target, uint32_t limit, + uint32_t interval) +{ + size_t opt_offset; + struct ofpbuf request; + struct tcmsg *tcmsg; + uint32_t otarget, olimit, ointerval; + int error; + + tc_del_qdisc(netdev); + + tcmsg = tc_make_request(netdev, RTM_NEWQDISC, + NLM_F_EXCL | NLM_F_CREATE, &request); + if (!tcmsg) { + return ENODEV; + } + tcmsg->tcm_handle = tc_make_handle(1, 0); + tcmsg->tcm_parent = TC_H_ROOT; + + otarget = target ? target : 5000; + olimit = limit ? limit : 10240; + ointerval = interval ? interval : 100000; + + nl_msg_put_string(&request, TCA_KIND, "codel"); + opt_offset = nl_msg_start_nested(&request, TCA_OPTIONS); + nl_msg_put_u32(&request, TCA_CODEL_TARGET, otarget); + nl_msg_put_u32(&request, TCA_CODEL_LIMIT, olimit); + nl_msg_put_u32(&request, TCA_CODEL_INTERVAL, ointerval); + nl_msg_end_nested(&request, opt_offset); + + error = tc_transact(&request, NULL); + if (error) { + VLOG_WARN_RL(&rl, "failed to replace %s qdisc, " + "target %u, limit %u, interval %u error %d(%s)", + netdev_get_name(netdev), + otarget, olimit, ointerval, + error, ovs_strerror(error)); + } + return error; +} + +static void +codel_parse_qdisc_details__(struct netdev *netdev OVS_UNUSED, + const struct smap *details, struct codel *codel) +{ + const char *target_s; + const char *limit_s; + const char *interval_s; + + target_s = smap_get(details, "target"); + limit_s = smap_get(details, "limit"); + interval_s = smap_get(details, "interval"); + + codel->target = target_s ? strtoull(target_s, NULL, 10) : 0; + codel->limit = limit_s ? strtoull(limit_s, NULL, 10) : 0; + codel->interval = interval_s ? strtoull(interval_s, NULL, 10) : 0; + + if (!codel->target) { + codel->target = 5000; + } + if (!codel->limit) { + codel->limit = 10240; + } + if (!codel->interval) { + codel->interval = 100000; + } +} + +static int +codel_tc_install(struct netdev *netdev, const struct smap *details) +{ + int error; + struct codel codel; + + codel_parse_qdisc_details__(netdev, details, &codel); + error = codel_setup_qdisc__(netdev, codel.target, codel.limit, + codel.interval); + if (!error) { + codel_install__(netdev, codel.target, codel.limit, codel.interval); + } + return error; +} + +static int +codel_parse_tca_options__(struct nlattr *nl_options, struct codel *codel) +{ + static const struct nl_policy tca_codel_policy[] = { + [TCA_CODEL_TARGET] = { .type = NL_A_U32 }, + [TCA_CODEL_LIMIT] = { .type = NL_A_U32 }, + [TCA_CODEL_INTERVAL] = { .type = NL_A_U32 } + }; + + struct nlattr *attrs[ARRAY_SIZE(tca_codel_policy)]; + + if (!nl_parse_nested(nl_options, tca_codel_policy, + attrs, ARRAY_SIZE(tca_codel_policy))) { + VLOG_WARN_RL(&rl, "failed to parse CoDel class options"); + return EPROTO; + } + + codel->target = nl_attr_get_u32(attrs[TCA_CODEL_TARGET]); + codel->limit = nl_attr_get_u32(attrs[TCA_CODEL_LIMIT]); + codel->interval = nl_attr_get_u32(attrs[TCA_CODEL_INTERVAL]); + return 0; +} + +static int +codel_tc_load(struct netdev *netdev, struct ofpbuf *nlmsg) +{ + struct nlattr *nlattr; + const char * kind; + int error; + struct codel codel; + + error = tc_parse_qdisc(nlmsg, &kind, &nlattr); + if (error != 0) { + return error; + } + + error = codel_parse_tca_options__(nlattr, &codel); + if (error != 0) { + return error; + } + + codel_install__(netdev, codel.target, codel.limit, codel.interval); + return 0; +} + + +static void +codel_tc_destroy(struct tc *tc) +{ + struct codel *codel = CONTAINER_OF(tc, struct codel, tc); + tc_destroy(tc); + free(codel); +} + +static int +codel_qdisc_get(const struct netdev *netdev, struct smap *details) +{ + const struct codel *codel = codel_get__(netdev); + smap_add_format(details, "target", "%u", codel->target); + smap_add_format(details, "limit", "%u", codel->limit); + smap_add_format(details, "interval", "%u", codel->interval); + return 0; +} + +static int +codel_qdisc_set(struct netdev *netdev, const struct smap *details) +{ + struct codel codel; + + codel_parse_qdisc_details__(netdev, details, &codel); + codel_install__(netdev, codel.target, codel.limit, codel.interval); + codel_get__(netdev)->target = codel.target; + codel_get__(netdev)->limit = codel.limit; + codel_get__(netdev)->interval = codel.interval; + return 0; +} + +static const struct tc_ops tc_ops_codel = { + "codel", /* linux_name */ + "linux-codel", /* ovs_name */ + CODEL_N_QUEUES, /* n_queues */ + codel_tc_install, + codel_tc_load, + codel_tc_destroy, + codel_qdisc_get, + codel_qdisc_set, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +/* FQ-CoDel traffic control class. */ + +#define FQCODEL_N_QUEUES 0x0000 + +struct fqcodel { + struct tc tc; + uint32_t target; + uint32_t limit; + uint32_t interval; + uint32_t flows; + uint32_t quantum; +}; + +static struct fqcodel * +fqcodel_get__(const struct netdev *netdev_) +{ + struct netdev_linux *netdev = netdev_linux_cast(netdev_); + return CONTAINER_OF(netdev->tc, struct fqcodel, tc); +} + +static void +fqcodel_install__(struct netdev *netdev_, uint32_t target, uint32_t limit, + uint32_t interval, uint32_t flows, uint32_t quantum) +{ + struct netdev_linux *netdev = netdev_linux_cast(netdev_); + struct fqcodel *fqcodel; + + fqcodel = xmalloc(sizeof *fqcodel); + tc_init(&fqcodel->tc, &tc_ops_fqcodel); + fqcodel->target = target; + fqcodel->limit = limit; + fqcodel->interval = interval; + fqcodel->flows = flows; + fqcodel->quantum = quantum; + + netdev->tc = &fqcodel->tc; +} + +static int +fqcodel_setup_qdisc__(struct netdev *netdev, uint32_t target, uint32_t limit, + uint32_t interval, uint32_t flows, uint32_t quantum) +{ + size_t opt_offset; + struct ofpbuf request; + struct tcmsg *tcmsg; + uint32_t otarget, olimit, ointerval, oflows, oquantum; + int error; + + tc_del_qdisc(netdev); + + tcmsg = tc_make_request(netdev, RTM_NEWQDISC, + NLM_F_EXCL | NLM_F_CREATE, &request); + if (!tcmsg) { + return ENODEV; + } + tcmsg->tcm_handle = tc_make_handle(1, 0); + tcmsg->tcm_parent = TC_H_ROOT; + + otarget = target ? target : 5000; + olimit = limit ? limit : 10240; + ointerval = interval ? interval : 100000; + oflows = flows ? flows : 1024; + oquantum = quantum ? quantum : 1514; /* fq_codel default quantum is 1514 + not mtu */ + + nl_msg_put_string(&request, TCA_KIND, "fq_codel"); + opt_offset = nl_msg_start_nested(&request, TCA_OPTIONS); + nl_msg_put_u32(&request, TCA_FQ_CODEL_TARGET, otarget); + nl_msg_put_u32(&request, TCA_FQ_CODEL_LIMIT, olimit); + nl_msg_put_u32(&request, TCA_FQ_CODEL_INTERVAL, ointerval); + nl_msg_put_u32(&request, TCA_FQ_CODEL_FLOWS, oflows); + nl_msg_put_u32(&request, TCA_FQ_CODEL_QUANTUM, oquantum); + nl_msg_end_nested(&request, opt_offset); + + error = tc_transact(&request, NULL); + if (error) { + VLOG_WARN_RL(&rl, "failed to replace %s qdisc, " + "target %u, limit %u, interval %u, flows %u, quantum %u error %d(%s)", + netdev_get_name(netdev), + otarget, olimit, ointerval, oflows, oquantum, + error, ovs_strerror(error)); + } + return error; +} + +static void +fqcodel_parse_qdisc_details__(struct netdev *netdev OVS_UNUSED, + const struct smap *details, struct fqcodel *fqcodel) +{ + const char *target_s; + const char *limit_s; + const char *interval_s; + const char *flows_s; + const char *quantum_s; + + target_s = smap_get(details, "target"); + limit_s = smap_get(details, "limit"); + interval_s = smap_get(details, "interval"); + flows_s = smap_get(details, "flows"); + quantum_s = smap_get(details, "quantum"); + fqcodel->target = target_s ? strtoull(target_s, NULL, 10) : 0; + fqcodel->limit = limit_s ? strtoull(limit_s, NULL, 10) : 0; + fqcodel->interval = interval_s ? strtoull(interval_s, NULL, 10) : 0; + fqcodel->flows = flows_s ? strtoull(flows_s, NULL, 10) : 0; + fqcodel->quantum = quantum_s ? strtoull(quantum_s, NULL, 10) : 0; + if (!fqcodel->target) { + fqcodel->target = 5000; + } + if (!fqcodel->limit) { + fqcodel->limit = 10240; + } + if (!fqcodel->interval) { + fqcodel->interval = 1000000; + } + if (!fqcodel->flows) { + fqcodel->flows = 1024; + } + if (!fqcodel->quantum) { + fqcodel->quantum = 1514; + } +} + +static int +fqcodel_tc_install(struct netdev *netdev, const struct smap *details) +{ + int error; + struct fqcodel fqcodel; + + fqcodel_parse_qdisc_details__(netdev, details, &fqcodel); + error = fqcodel_setup_qdisc__(netdev, fqcodel.target, fqcodel.limit, + fqcodel.interval, fqcodel.flows, + fqcodel.quantum); + if (!error) { + fqcodel_install__(netdev, fqcodel.target, fqcodel.limit, + fqcodel.interval, fqcodel.flows, fqcodel.quantum); + } + return error; +} + +static int +fqcodel_parse_tca_options__(struct nlattr *nl_options, struct fqcodel *fqcodel) +{ + static const struct nl_policy tca_fqcodel_policy[] = { + [TCA_FQ_CODEL_TARGET] = { .type = NL_A_U32 }, + [TCA_FQ_CODEL_LIMIT] = { .type = NL_A_U32 }, + [TCA_FQ_CODEL_INTERVAL] = { .type = NL_A_U32 }, + [TCA_FQ_CODEL_FLOWS] = { .type = NL_A_U32 }, + [TCA_FQ_CODEL_QUANTUM] = { .type = NL_A_U32 } + }; + + struct nlattr *attrs[ARRAY_SIZE(tca_fqcodel_policy)]; + + if (!nl_parse_nested(nl_options, tca_fqcodel_policy, + attrs, ARRAY_SIZE(tca_fqcodel_policy))) { + VLOG_WARN_RL(&rl, "failed to parse FQ_CoDel class options"); + return EPROTO; + } + + fqcodel->target = nl_attr_get_u32(attrs[TCA_FQ_CODEL_TARGET]); + fqcodel->limit = nl_attr_get_u32(attrs[TCA_FQ_CODEL_LIMIT]); + fqcodel->interval =nl_attr_get_u32(attrs[TCA_FQ_CODEL_INTERVAL]); + fqcodel->flows = nl_attr_get_u32(attrs[TCA_FQ_CODEL_FLOWS]); + fqcodel->quantum = nl_attr_get_u32(attrs[TCA_FQ_CODEL_QUANTUM]); + return 0; +} + +static int +fqcodel_tc_load(struct netdev *netdev, struct ofpbuf *nlmsg) +{ + struct nlattr *nlattr; + const char * kind; + int error; + struct fqcodel fqcodel; + + error = tc_parse_qdisc(nlmsg, &kind, &nlattr); + if (error != 0) { + return error; + } + + error = fqcodel_parse_tca_options__(nlattr, &fqcodel); + if (error != 0) { + return error; + } + + fqcodel_install__(netdev, fqcodel.target, fqcodel.limit, fqcodel.interval, + fqcodel.flows, fqcodel.quantum); + return 0; +} + +static void +fqcodel_tc_destroy(struct tc *tc) +{ + struct fqcodel *fqcodel = CONTAINER_OF(tc, struct fqcodel, tc); + tc_destroy(tc); + free(fqcodel); +} + +static int +fqcodel_qdisc_get(const struct netdev *netdev, struct smap *details) +{ + const struct fqcodel *fqcodel = fqcodel_get__(netdev); + smap_add_format(details, "target", "%u", fqcodel->target); + smap_add_format(details, "limit", "%u", fqcodel->limit); + smap_add_format(details, "interval", "%u", fqcodel->interval); + smap_add_format(details, "flows", "%u", fqcodel->flows); + smap_add_format(details, "quantum", "%u", fqcodel->quantum); + return 0; +} + +static int +fqcodel_qdisc_set(struct netdev *netdev, const struct smap *details) +{ + struct fqcodel fqcodel; + + fqcodel_parse_qdisc_details__(netdev, details, &fqcodel); + fqcodel_install__(netdev, fqcodel.target, fqcodel.limit, fqcodel.interval, + fqcodel.flows, fqcodel.quantum); + fqcodel_get__(netdev)->target = fqcodel.target; + fqcodel_get__(netdev)->limit = fqcodel.limit; + fqcodel_get__(netdev)->interval = fqcodel.interval; + fqcodel_get__(netdev)->flows = fqcodel.flows; + fqcodel_get__(netdev)->quantum = fqcodel.quantum; + return 0; +} + +static const struct tc_ops tc_ops_fqcodel = { + "fq_codel", /* linux_name */ + "linux-fq_codel", /* ovs_name */ + FQCODEL_N_QUEUES, /* n_queues */ + fqcodel_tc_install, + fqcodel_tc_load, + fqcodel_tc_destroy, + fqcodel_qdisc_get, + fqcodel_qdisc_set, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +/* SFQ traffic control class. */ + +#define SFQ_N_QUEUES 0x0000 + +struct sfq { + struct tc tc; + uint32_t quantum; + uint32_t perturb; +}; + +static struct sfq * +sfq_get__(const struct netdev *netdev_) +{ + struct netdev_linux *netdev = netdev_linux_cast(netdev_); + return CONTAINER_OF(netdev->tc, struct sfq, tc); +} + +static void +sfq_install__(struct netdev *netdev_, uint32_t quantum, uint32_t perturb) +{ + struct netdev_linux *netdev = netdev_linux_cast(netdev_); + struct sfq *sfq; + + sfq = xmalloc(sizeof *sfq); + tc_init(&sfq->tc, &tc_ops_sfq); + sfq->perturb = perturb; + sfq->quantum = quantum; + + netdev->tc = &sfq->tc; +} + +static int +sfq_setup_qdisc__(struct netdev *netdev, uint32_t quantum, uint32_t perturb) +{ + struct tc_sfq_qopt opt; + struct ofpbuf request; + struct tcmsg *tcmsg; + int mtu; + int mtu_error, error; + mtu_error = netdev_linux_get_mtu__(netdev_linux_cast(netdev), &mtu); + + tc_del_qdisc(netdev); + + tcmsg = tc_make_request(netdev, RTM_NEWQDISC, + NLM_F_EXCL | NLM_F_CREATE, &request); + if (!tcmsg) { + return ENODEV; + } + tcmsg->tcm_handle = tc_make_handle(1, 0); + tcmsg->tcm_parent = TC_H_ROOT; + + memset(&opt, 0, sizeof opt); + if (!quantum) { + if (!mtu_error) { + opt.quantum = mtu; /* if we cannot find mtu, use default */ + } + } else { + opt.quantum = quantum; + } + + if (!perturb) { + opt.perturb_period = 10; + } else { + opt.perturb_period = perturb; + } + + nl_msg_put_string(&request, TCA_KIND, "sfq"); + nl_msg_put_unspec(&request, TCA_OPTIONS, &opt, sizeof opt); + + error = tc_transact(&request, NULL); + if (error) { + VLOG_WARN_RL(&rl, "failed to replace %s qdisc, " + "quantum %u, perturb %u error %d(%s)", + netdev_get_name(netdev), + opt.quantum, opt.perturb_period, + error, ovs_strerror(error)); + } + return error; +} + +static void +sfq_parse_qdisc_details__(struct netdev *netdev, + const struct smap *details, struct sfq *sfq) +{ + const char *perturb_s; + const char *quantum_s; + int mtu; + int mtu_error; + + perturb_s = smap_get(details, "perturb"); + quantum_s = smap_get(details, "quantum"); + sfq->perturb = perturb_s ? strtoull(perturb_s, NULL, 10) : 0; + sfq->quantum = quantum_s ? strtoull(quantum_s, NULL, 10) : 0; + if (!sfq->perturb) { + sfq->perturb = 10; + } + + if (!sfq->quantum) { + mtu_error = netdev_linux_get_mtu__(netdev_linux_cast(netdev), &mtu); + if (!mtu_error) { + sfq->quantum = mtu; + } else { + VLOG_WARN_RL(&rl, "when using SFQ, you must specify quantum on a " + "device without mtu"); + return; + } + } +} + +static int +sfq_tc_install(struct netdev *netdev, const struct smap *details) +{ + int error; + struct sfq sfq; + + sfq_parse_qdisc_details__(netdev, details, &sfq); + error = sfq_setup_qdisc__(netdev, sfq.quantum, sfq.perturb); + if (!error) { + sfq_install__(netdev, sfq.quantum, sfq.perturb); + } + return error; +} + +static int +sfq_tc_load(struct netdev *netdev, struct ofpbuf *nlmsg) +{ + const struct tc_sfq_qopt *sfq; + struct nlattr *nlattr; + const char * kind; + int error; + + error = tc_parse_qdisc(nlmsg, &kind, &nlattr); + if (error == 0) { + sfq = nl_attr_get(nlattr); + sfq_install__(netdev, sfq->perturb_period, sfq->quantum); + return 0; + } + + return error; +} + +static void +sfq_tc_destroy(struct tc *tc) +{ + struct sfq *sfq = CONTAINER_OF(tc, struct sfq, tc); + tc_destroy(tc); + free(sfq); +} + +static int +sfq_qdisc_get(const struct netdev *netdev, struct smap *details) +{ + const struct sfq *sfq = sfq_get__(netdev); + smap_add_format(details, "quantum", "%u", sfq->quantum); + smap_add_format(details, "perturb", "%u", sfq->perturb); + return 0; +} + +static int +sfq_qdisc_set(struct netdev *netdev, const struct smap *details) +{ + struct sfq sfq; + + sfq_parse_qdisc_details__(netdev, details, &sfq); + sfq_install__(netdev, sfq.quantum, sfq.perturb); + sfq_get__(netdev)->quantum = sfq.quantum; + sfq_get__(netdev)->perturb = sfq.perturb; + return 0; +} + +static const struct tc_ops tc_ops_sfq = { + "sfq", /* linux_name */ + "linux-sfq", /* ovs_name */ + SFQ_N_QUEUES, /* n_queues */ + sfq_tc_install, + sfq_tc_load, + sfq_tc_destroy, + sfq_qdisc_get, + sfq_qdisc_set, + NULL, + NULL, + NULL, + NULL, + NULL +}; + /* HTB traffic control class. */ #define HTB_N_QUEUES 0xf000 diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index 68648b9bc..4213a7902 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -4382,7 +4382,7 @@ iface_configure_qos(struct iface *iface, const struct ovsrec_qos *qos) ofpbuf_init(&queues_buf, 0); - if (!qos || qos->type[0] == '\0' || qos->n_queues < 1) { + if (!qos || qos->type[0] == '\0') { netdev_set_qos(iface->netdev, NULL, NULL); } else { const struct ovsdb_datum *queues; diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml index 1bd652217..07f3bea4a 100644 --- a/vswitchd/vswitch.xml +++ b/vswitchd/vswitch.xml @@ -3149,6 +3149,33 @@ information on how this classifier works. +
+
linux-sfq
+
+ Linux ``Stochastic Fairness Queueing'' classifier. See + tc-sfq(8) (also at + http://linux.die.net/man/8/tc-sfq) for information on + how this classifier works. +
+
+
+
linux-codel
+
+ Linux ``Controlled Delay'' classifier. See tc-codel(8) + (also at + http://man7.org/linux/man-pages/man8/tc-codel.8.html) + for information on how this classifier works. +
+
+
+
linux-fq_codel
+
+ Linux ``Fair Queuing with Controlled Delay'' classifier. See + tc-fq_codel(8) (also at + http://man7.org/linux/man-pages/man8/tc-fq_codel.8.html) + for information on how this classifier works. +
+
-- cgit v1.2.1 From 59a33335dcc5c750b55dbd2a7961e91a816697b7 Mon Sep 17 00:00:00 2001 From: Sorin Vinturis Date: Tue, 24 Mar 2015 14:53:11 +0000 Subject: datapath-windows: Updated WFP system provider handling If the Base Filtering Engine (BFE) is not started, the WFP system provider failed to be added because no session to the engine could be acquired. The solution for this was to registered a BFE notification callback that is called whenever the BFE's state changes. Only if the BFE's state is running the WFP system provider is added. Signed-off-by: Sorin Vinturis Reported-by: Sorin Vinturis Reported-at: https://github.com/openvswitch/ovs-issues/issues/65 Acked-by: Eitan Eliahu Signed-off-by: Ben Pfaff --- datapath-windows/ovsext/Datapath.c | 20 ++----- datapath-windows/ovsext/TunnelFilter.c | 99 ++++++++++++++++++++++++++++++++-- datapath-windows/ovsext/TunnelIntf.h | 8 +-- 3 files changed, 100 insertions(+), 27 deletions(-) diff --git a/datapath-windows/ovsext/Datapath.c b/datapath-windows/ovsext/Datapath.c index 8eb13f14a..c6fe89eb7 100644 --- a/datapath-windows/ovsext/Datapath.c +++ b/datapath-windows/ovsext/Datapath.c @@ -353,35 +353,19 @@ PNDIS_SPIN_LOCK gOvsCtrlLock; VOID OvsInit() { - HANDLE handle = NULL; - gOvsCtrlLock = &ovsCtrlLockObj; NdisAllocateSpinLock(gOvsCtrlLock); OvsInitEventQueue(); - - OvsTunnelEngineOpen(&handle); - if (handle) { - OvsTunnelAddSystemProvider(handle); - } - OvsTunnelEngineClose(&handle); } VOID OvsCleanup() { - HANDLE handle = NULL; - OvsCleanupEventQueue(); if (gOvsCtrlLock) { NdisFreeSpinLock(gOvsCtrlLock); gOvsCtrlLock = NULL; } - - OvsTunnelEngineOpen(&handle); - if (handle) { - OvsTunnelRemoveSystemProvider(handle); - } - OvsTunnelEngineClose(&handle); } VOID @@ -448,6 +432,8 @@ OvsCreateDeviceObject(NDIS_HANDLE ovsExtDriverHandle) if (ovsExt) { ovsExt->numberOpenInstance = 0; } + } else { + OvsRegisterSystemProvider((PVOID)gOvsDeviceObject); } OVS_LOG_TRACE("DeviceObject: %p", gOvsDeviceObject); @@ -471,6 +457,8 @@ OvsDeleteDeviceObject() NdisDeregisterDeviceEx(gOvsDeviceHandle); gOvsDeviceHandle = NULL; gOvsDeviceObject = NULL; + + OvsUnregisterSystemProvider(); } } diff --git a/datapath-windows/ovsext/TunnelFilter.c b/datapath-windows/ovsext/TunnelFilter.c index e0adc3726..4b879c059 100644 --- a/datapath-windows/ovsext/TunnelFilter.c +++ b/datapath-windows/ovsext/TunnelFilter.c @@ -111,6 +111,7 @@ DEFINE_GUID( PDEVICE_OBJECT gDeviceObject; HANDLE gEngineHandle = NULL; +HANDLE gBfeSubscriptionHandle = NULL; UINT32 gCalloutIdV4; @@ -173,17 +174,20 @@ OvsTunnelAddSystemProvider(HANDLE handle) provider.displayData.name = OVS_TUNNEL_PROVIDER_NAME; provider.displayData.description = OVS_TUNNEL_PROVIDER_DESC; /* - * Since we always want the provider to be present, it's easiest to add - * it as persistent object during driver load. - */ + * Since we always want the provider to be present, it's easiest to add + * it as persistent object during driver load. + */ provider.flags = FWPM_PROVIDER_FLAG_PERSISTENT; status = FwpmProviderAdd(handle, &provider, NULL); if (!NT_SUCCESS(status)) { - OVS_LOG_ERROR("Fail to add WFP provider, status: %x.", status); - break; + if (STATUS_FWP_ALREADY_EXISTS != status) { + OVS_LOG_ERROR("Failed to add WFP provider, status: %x.", + status); + break; + } } status = FwpmTransactionCommit(handle); @@ -541,3 +545,88 @@ Exit: return status; } + +VOID NTAPI +OvsBfeStateChangeCallback(PVOID context, + FWPM_SERVICE_STATE bfeState) +{ + HANDLE handle = NULL; + + DBG_UNREFERENCED_PARAMETER(context); + + if (FWPM_SERVICE_RUNNING == bfeState) { + OvsTunnelEngineOpen(&handle); + if (handle) { + OvsTunnelAddSystemProvider(handle); + } + OvsTunnelEngineClose(&handle); + } +} + +NTSTATUS +OvsSubscribeBfeStateChanges(PVOID deviceObject) +{ + NTSTATUS status = STATUS_SUCCESS; + + if (!gBfeSubscriptionHandle) { + status = FwpmBfeStateSubscribeChanges(deviceObject, + OvsBfeStateChangeCallback, + NULL, + &gBfeSubscriptionHandle); + if (!NT_SUCCESS(status)) { + OVS_LOG_ERROR( + "Failed to open subscribe BFE state change callback, status: %x.", + status); + } + } + + return status; +} + +VOID +OvsUnsubscribeBfeStateChanges() +{ + NTSTATUS status = STATUS_SUCCESS; + + if (gBfeSubscriptionHandle) { + status = FwpmBfeStateUnsubscribeChanges(gBfeSubscriptionHandle); + if (!NT_SUCCESS(status)) { + OVS_LOG_ERROR( + "Failed to open unsubscribe BFE state change callback, status: %x.", + status); + } + gBfeSubscriptionHandle = NULL; + } +} + +VOID OvsRegisterSystemProvider(PVOID deviceObject) +{ + NTSTATUS status = STATUS_SUCCESS; + HANDLE handle = NULL; + + status = OvsSubscribeBfeStateChanges(deviceObject); + if (NT_SUCCESS(status)) { + if (FWPM_SERVICE_RUNNING == FwpmBfeStateGet()) { + OvsTunnelEngineOpen(&handle); + if (handle) { + OvsTunnelAddSystemProvider(handle); + } + OvsTunnelEngineClose(&handle); + + OvsUnsubscribeBfeStateChanges(); + } + } +} + +VOID OvsUnregisterSystemProvider() +{ + HANDLE handle = NULL; + + OvsTunnelEngineOpen(&handle); + if (handle) { + OvsTunnelRemoveSystemProvider(handle); + } + OvsTunnelEngineClose(&handle); + + OvsUnsubscribeBfeStateChanges(); +} diff --git a/datapath-windows/ovsext/TunnelIntf.h b/datapath-windows/ovsext/TunnelIntf.h index b2bba308e..728a53f7f 100644 --- a/datapath-windows/ovsext/TunnelIntf.h +++ b/datapath-windows/ovsext/TunnelIntf.h @@ -22,12 +22,8 @@ NTSTATUS OvsTunnelFilterInitialize(PDRIVER_OBJECT driverObject); VOID OvsTunnelFilterUninitialize(PDRIVER_OBJECT driverObject); -NTSTATUS OvsTunnelEngineOpen(HANDLE *handle); +VOID OvsRegisterSystemProvider(PVOID deviceObject); -VOID OvsTunnelEngineClose(HANDLE *handle); - -VOID OvsTunnelAddSystemProvider(HANDLE handle); - -VOID OvsTunnelRemoveSystemProvider(HANDLE handle); +VOID OvsUnregisterSystemProvider(); #endif /* __TUNNEL_INTF_H_ */ -- cgit v1.2.1 From 842733c37ccb51d574795782143ed99b0a76a44d Mon Sep 17 00:00:00 2001 From: "Mark D. Gray" Date: Tue, 24 Mar 2015 10:39:11 +0000 Subject: vswitch.ovsschema: Add datapath_types and port_types. At startup enumerate datapath and port types and add this information to the datapath_types and port_types columns in the ovsdb. This allows an ovsdb client to query the datapath in order to determine if certain datapath and port types exist. For example, by querying the port_types column, an ovsdb client will be able to determine if this instance of ovs-vswitchd was compiled with DPDK support. Signed-off-by: Mark D. Gray Signed-off-by: Billy O'Mahony [blp@nicira.com made several changes] Signed-off-by: Ben Pfaff --- lib/sset.c | 38 ++++++++++++++++++++++++-------------- lib/sset.h | 3 ++- vswitchd/bridge.c | 40 ++++++++++++++++++++++++++++++++++++++++ vswitchd/vswitch.ovsschema | 12 +++++++++--- vswitchd/vswitch.xml | 36 ++++++++++++++++++++++++++++++++---- 5 files changed, 107 insertions(+), 22 deletions(-) diff --git a/lib/sset.c b/lib/sset.c index 443538d64..33c42989a 100644 --- a/lib/sset.c +++ b/lib/sset.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, 2013 Nicira, Inc. + * Copyright (c) 2011, 2012, 2013, 2015 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -269,21 +269,12 @@ sset_at_position(const struct sset *set, uint32_t *bucketp, uint32_t *offsetp) return SSET_NODE_FROM_HMAP_NODE(hmap_node); } -static int -compare_string_pointers(const void *a_, const void *b_) -{ - const char *const *a = a_; - const char *const *b = b_; - - return strcmp(*a, *b); -} - -/* Returns a null-terminated array of pointers to the strings in 'set', sorted - * alphabetically. The caller must free the returned array when it is no +/* Returns a null-terminated array of pointers to the strings in 'set', in no + * particular order. The caller must free the returned array when it is no * longer needed, but the strings in the array belong to 'set' and thus must * not be modified or freed. */ const char ** -sset_sort(const struct sset *set) +sset_array(const struct sset *set) { size_t n = sset_count(set); const char **array; @@ -298,7 +289,26 @@ sset_sort(const struct sset *set) ovs_assert(i == n); array[n] = NULL; - qsort(array, n, sizeof *array, compare_string_pointers); + return array; +} + +static int +compare_string_pointers(const void *a_, const void *b_) +{ + const char *const *a = a_; + const char *const *b = b_; + + return strcmp(*a, *b); +} +/* Returns a null-terminated array of pointers to the strings in 'set', sorted + * alphabetically. The caller must free the returned array when it is no + * longer needed, but the strings in the array belong to 'set' and thus must + * not be modified or freed. */ +const char ** +sset_sort(const struct sset *set) +{ + const char **array = sset_array(set); + qsort(array, sset_count(set), sizeof *array, compare_string_pointers); return array; } diff --git a/lib/sset.h b/lib/sset.h index 1e864efce..35bf46320 100644 --- a/lib/sset.h +++ b/lib/sset.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, 2013 Nicira, Inc. + * Copyright (c) 2011, 2012, 2013, 2015 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -80,6 +80,7 @@ struct sset_node *sset_at_position(const struct sset *, : false); \ (NAME) = (NEXT)) +const char **sset_array(const struct sset *); const char **sset_sort(const struct sset *); /* Implementation helper macros. */ diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index 4213a7902..2e90ea22c 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -18,6 +18,7 @@ #include #include #include + #include "async-append.h" #include "bfd.h" #include "bitmap.h" @@ -26,6 +27,7 @@ #include "coverage.h" #include "daemon.h" #include "dirs.h" +#include "dpif.h" #include "dynamic-string.h" #include "hash.h" #include "hmap.h" @@ -317,6 +319,7 @@ static ofp_port_t iface_get_requested_ofp_port( const struct ovsrec_interface *); static ofp_port_t iface_pick_ofport(const struct ovsrec_interface *); + /* Linux VLAN device support (e.g. "eth0.10" for VLAN 10.) * * This is deprecated. It is only for compatibility with broken device drivers @@ -335,6 +338,8 @@ static void add_vlan_splinter_ports(struct bridge *, const unsigned long int *splinter_vlans, struct shash *ports); +static void discover_types(const struct ovsrec_open_vswitch *cfg); + static void bridge_init_ofproto(const struct ovsrec_open_vswitch *cfg) { @@ -394,6 +399,8 @@ bridge_init(const char *remote) ovsdb_idl_omit_alert(idl, &ovsrec_open_vswitch_col_cur_cfg); ovsdb_idl_omit_alert(idl, &ovsrec_open_vswitch_col_statistics); + ovsdb_idl_omit_alert(idl, &ovsrec_open_vswitch_col_datapath_types); + ovsdb_idl_omit_alert(idl, &ovsrec_open_vswitch_col_iface_types); ovsdb_idl_omit(idl, &ovsrec_open_vswitch_col_external_ids); ovsdb_idl_omit(idl, &ovsrec_open_vswitch_col_ovs_version); ovsdb_idl_omit(idl, &ovsrec_open_vswitch_col_db_version); @@ -571,6 +578,10 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg) smap_get_int(&ovs_cfg->other_config, "n-handler-threads", 0), smap_get_int(&ovs_cfg->other_config, "n-revalidator-threads", 0)); + if (ovs_cfg) { + discover_types(ovs_cfg); + } + /* Destroy "struct bridge"s, "struct port"s, and "struct iface"s according * to 'ovs_cfg', with only very minimal configuration otherwise. * @@ -2940,6 +2951,7 @@ bridge_run(void) if (cfg) { ovsrec_open_vswitch_set_cur_cfg(cfg, cfg->next_cfg); + discover_types(cfg); } /* If we are completing our initial configuration for this run @@ -5023,3 +5035,31 @@ mirror_refresh_stats(struct mirror *m) ovsrec_mirror_set_statistics(m->cfg, keys, values, stat_cnt); } + +/* + * Add registered netdev and dpif types to ovsdb to allow external + * applications to query the capabilities of the Open vSwitch instance + * running on the node. + */ +static void +discover_types(const struct ovsrec_open_vswitch *cfg) +{ + struct sset types; + + /* Datapath types. */ + sset_init(&types); + dp_enumerate_types(&types); + const char **datapath_types = sset_array(&types); + ovsrec_open_vswitch_set_datapath_types(cfg, datapath_types, + sset_count(&types)); + free(datapath_types); + sset_destroy(&types); + + /* Port types. */ + sset_init(&types); + netdev_enumerate_types(&types); + const char **iface_types = sset_array(&types); + ovsrec_open_vswitch_set_iface_types(cfg, iface_types, sset_count(&types)); + free(iface_types); + sset_destroy(&types); +} diff --git a/vswitchd/vswitch.ovsschema b/vswitchd/vswitch.ovsschema index 4898b16d0..35f145f5d 100644 --- a/vswitchd/vswitch.ovsschema +++ b/vswitchd/vswitch.ovsschema @@ -1,6 +1,6 @@ {"name": "Open_vSwitch", - "version": "7.11.2", - "cksum": "320332148 22294", + "version": "7.12.1", + "cksum": "2211824403 22535", "tables": { "Open_vSwitch": { "columns": { @@ -39,7 +39,13 @@ "min": 0, "max": 1}}, "system_version": { "type": {"key": {"type": "string"}, - "min": 0, "max": 1}}}, + "min": 0, "max": 1}}, + "datapath_types": { + "type": {"key": {"type": "string"}, + "min": 0, "max": "unlimited"}}, + "iface_types": { + "type": {"key": {"type": "string"}, + "min": 0, "max": "unlimited"}}}, "isRoot": true, "maxRows": 1}, "Bridge": { diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml index 07f3bea4a..e04aefc3e 100644 --- a/vswitchd/vswitch.xml +++ b/vswitchd/vswitch.xml @@ -423,6 +423,28 @@ + +

+ These columns report capabilities of the Open vSwitch instance. +

+ +

+ This column reports the different dpifs registered with the system. + These are the values that this instance supports in the column of the table. +

+
+ +

+ This column reports the different netdevs registered with the system. + These are the values that this instance supports in the column of the table. +

+
+
+

These columns primarily configure the Open vSwitch database @@ -928,9 +950,12 @@ - Name of datapath provider. The kernel datapath has - type system. The userspace datapath has - type netdev. + Name of datapath provider. The kernel datapath has type + system. The userspace datapath has type + netdev. A manager may refer to the column of the table for a list of the types accepted by this + Open vSwitch instance. @@ -1747,7 +1772,10 @@

- The interface type, one of: + The interface type. The types supported by a particular instance of + Open vSwitch are listed in the column in the + table. The following types are defined:

-- cgit v1.2.1 From 89a994c9e7b2bb0ed4259e560c2a8926d51f02ba Mon Sep 17 00:00:00 2001 From: Oleg Gashev Date: Mon, 23 Mar 2015 21:54:48 +0000 Subject: rhel: Fix RPM build errors. On exec rpmbuild -ba openvswitch-fedora.spec displayed: error: Installed (but unpackaged) file(s) found: /etc/bash_completion.d/ovs-appctl-bashcomp.bash /etc/bash_completion.d/ovs-vsctl-bashcomp.bash RPM build errors: Installed (but unpackaged) file(s) found: /etc/bash_completion.d/ovs-appctl-bashcomp.bash /etc/bash_completion.d/ovs-vsctl-bashcomp.bash /etc/bash_completion.d/ovs-appctl-bashcomp.bash and /etc/bash_completion.d/ovs-vsctl-bashcomp.bash added to files list. Signed-off-by: Oleg Gashev Acked-by: Alex Wang Signed-off-by: Ben Pfaff --- rhel/openvswitch-fedora.spec.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rhel/openvswitch-fedora.spec.in b/rhel/openvswitch-fedora.spec.in index 5a3af4a15..4889321a4 100644 --- a/rhel/openvswitch-fedora.spec.in +++ b/rhel/openvswitch-fedora.spec.in @@ -200,6 +200,8 @@ rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root) +%{_sysconfdir}/bash_completion.d/ovs-appctl-bashcomp.bash +%{_sysconfdir}/bash_completion.d/ovs-vsctl-bashcomp.bash %dir %{_sysconfdir}/openvswitch %config %ghost %{_sysconfdir}/openvswitch/conf.db %config %ghost %{_sysconfdir}/openvswitch/system-id.conf -- cgit v1.2.1 From 8c254406a36cf87a6665566130a1b1838d2229bd Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Fri, 20 Mar 2015 13:50:28 +0900 Subject: Documentation: Add documentation of group selection method property NTR selection method Signed-off-by: Simon Horman Acked-by: Ben Pfaff Signed-off-by: Ben Pfaff --- Documentation/automake.mk | 2 + Documentation/group-selection-method-property.txt | 153 ++++++++++++++++++++++ Makefile.am | 1 + 3 files changed, 156 insertions(+) create mode 100644 Documentation/automake.mk create mode 100644 Documentation/group-selection-method-property.txt diff --git a/Documentation/automake.mk b/Documentation/automake.mk new file mode 100644 index 000000000..e5048018b --- /dev/null +++ b/Documentation/automake.mk @@ -0,0 +1,2 @@ +EXTRA_DIST += \ + Documentation/group-selection-method-property.txt diff --git a/Documentation/group-selection-method-property.txt b/Documentation/group-selection-method-property.txt new file mode 100644 index 000000000..36337c6b5 --- /dev/null +++ b/Documentation/group-selection-method-property.txt @@ -0,0 +1,153 @@ +Proposal for Group Selection Method Property +Version: 0.0.3 + +Author: Simon Horman , et al. +Initial Public Revision: September 2014 + + +Contents +======== + +1. Introduction +2. How it Works +3. Experimenter Id +4. Experimenter Messages +5. History + + +1. Introduction +=============== + +This text describes a Netronome Extension to (draft) OpenFlow 1.5 that allows a +controller to provide more information on the selection method for select +groups. This proposal is in the form of an enhanced select group type. + +This may subsequently be proposed as an extension or update to +the OpenFlow specification. + + +2. How it works +=============== + +A new Netronome group experimenter property is defined which provides +compatibility with the group mod message defined in draft Open Flow 1.5 +(also known as ONF EXT-350) and allows parameters for the selection +method of select groups to be passed by the controller. In particular it +allows controllers to: + +* Specify the fields used for bucket selection by the select group. + +* Designate the selection method used. + +* Provide a non-field parameter to the selection method. + + +3. Experimenter ID +================== + +The Experimenter ID of this extension is: + +NTR_VENDOR_ID = 0x00001540 + + +4. Group Experimenter Property +============================== + +The following group property experimenter type defined by this extension. + +enum ntr_group_mod_subtype { + NTRT_SELECTION_METHOD = 1, +}; + + +Modifications to the group table from the controller may be done with a +OFPT_GROUP_MOD message described (draft) Open Flow 1.5. Group Entry +Message. Of relevance here is that (draft) Open Flow 1.5 group messages +have properties. + +This proposal is defined in terms of an implementation of struct +ofp_group_prop_experimenter which is described in (draft) Open Flow 1.5. +The implementation is: + +struct ntr_group_prop_selection_method { + ovs_be16 type; /* OFPGPT_EXPERIMENTER. */ + ovs_be16 length; /* Length in bytes of this property. */ + ovs_be32 experimenter; /* NTR_VENDOR_ID. */ + ovs_be32 exp_type; /* NTRT_SELECTION_METHOD. */ + ovs_be32 pad; + char selection_method[NTR_MAX_SELECTION_METHOD_LEN]; + /* Null-terminated */ + ovs_be64 selection_method_param; /* Non-Field parameter for + * bucket selection. */ + + /* Followed by: + * - Exactly (length - 40) (possibly 0) bytes containing OXM TLVs, then + * - Exactly ((length + 7)/8*8 - length) (between 0 and 7) bytes of + * all-zero bytes + * In summary, ntr_group_prop_selection_method is padded as needed, + * to make its overall size a multiple of 8, to preserve alignment + * in structures using it. + */ + /* uint8_t field_array[0]; */ /* Zero or more fields encoded as + * OXM TLVs where the has_mask bit must + * be zero and the value it specifies is + * a mask to apply to packet fields and + * then input them to the selection + * method of a select group. */ + /* uint8_t pad2[0]; */ +}; +OFP_ASSERT(sizeof(struct ntr_group_mod) == 40); + + +This property may only be used with group mod messages whose: +* command is OFPGC_ADD or OFPGC_MODIFY; and +* type is OFPGT_SELECT + + +The type field is the OFPGPT_EXPERIMENTER which is +defined in EXT-350 as 0xffff. + + +The experimenter field is the Experimenter ID (see 3). + + +The exp_type field is NTRT_SELECTION_METHOD. + + +The group selection_method is a null-terminated string which if non-zero +length specifies a selection method known to an underlying layer of the +switch. The value of NTR_MAX_SELECTION_METHOD_LEN is 16. + +The group selection_method may be zero-length to request compatibility with +Open Flow 1.4. + + +The selection_method_param provides a non-field parameter for +the group selection_method. It must be all-zeros unless the +group selection_method is non-zero length. + +The selection_method_param may for example be used as an initial value for +the hash of a hash group selection method. + + +The fields field is an ofp_match structure which includes the fields which +should be used as inputs to bucket selection. ofp_match is described in +Open Flow 1.4 section 7.2.2 Flow Match Structures. + +Fields must not be specified unless the group selection_method is non-zero +length. + +The pre-requisites for fields specified must be satisfied in the match for +any flow that uses the group. + +Masking is allowed but not required for fields whose TLVs allow masking. + +The fields may for example be used as the fields that are hashed +by a hash group selection method. + + +5. History +========== + +This proposal has been developed independently of any similar work in this +area. No such work is known. diff --git a/Makefile.am b/Makefile.am index ab2216749..cada99707 100644 --- a/Makefile.am +++ b/Makefile.am @@ -358,6 +358,7 @@ dist-docs: VERSION=$(VERSION) $(srcdir)/build-aux/dist-docs $(srcdir) $(docs) .PHONY: dist-docs +include Documentation/automake.mk include m4/automake.mk include lib/automake.mk include ofproto/automake.mk -- cgit v1.2.1 From 4aa6cf580bc1292e4e7dd5ec42802ed99311cd6b Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Fri, 20 Mar 2015 13:50:29 +0900 Subject: Add types for NTR selection method NTR selection method Signed-off-by: Simon Horman Signed-off-by: Ben Pfaff --- include/openflow/automake.mk | 1 + include/openflow/netronome-ext.h | 66 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 include/openflow/netronome-ext.h diff --git a/include/openflow/automake.mk b/include/openflow/automake.mk index 50933d5be..d7dac9132 100644 --- a/include/openflow/automake.mk +++ b/include/openflow/automake.mk @@ -1,5 +1,6 @@ openflowincludedir = $(includedir)/openflow openflowinclude_HEADERS = \ + include/openflow/netronome-ext.h \ include/openflow/nicira-ext.h \ include/openflow/openflow-1.0.h \ include/openflow/openflow-1.1.h \ diff --git a/include/openflow/netronome-ext.h b/include/openflow/netronome-ext.h new file mode 100644 index 000000000..8db7b79fc --- /dev/null +++ b/include/openflow/netronome-ext.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2014 Netronome. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OPENFLOW_NETRONOME_EXT_H +#define OPENFLOW_NETRONOME_EXT_H 1 + +#include "openflow/openflow.h" +#include "openvswitch/types.h" + +/* The following vendor extension, proposed by Netronome, is not yet + * standardized, so they are not included in openflow.h. It may + * be suitable for standardization */ + + +/* Netronome enhanced select group */ + +enum ntr_group_mod_subtype { + NTRT_SELECTION_METHOD = 1, +}; + +#define NTR_MAX_SELECTION_METHOD_LEN 16 + +struct ntr_group_prop_selection_method { + ovs_be16 type; /* OFPGPT15_EXPERIMENTER. */ + ovs_be16 length; /* Length in bytes of this property + * excluding trailing padding. */ + ovs_be32 experimenter; /* NTR_VENDOR_ID. */ + ovs_be32 exp_type; /* NTRT_SELECTION_METHOD. */ + ovs_be32 pad; + char selection_method[NTR_MAX_SELECTION_METHOD_LEN]; + /* Null-terminated */ + ovs_be64 selection_method_param; /* Non-Field parameter for + * bucket selection. */ + + /* Followed by: + * - Exactly (length - 40) (possibly 0) bytes containing OXM TLVs, then + * - Exactly ((length + 7)/8*8 - length) (between 0 and 7) bytes of + * all-zero bytes + * In summary, ntr_group_prop_selection_method is padded as needed, + * to make its overall size a multiple of 8, to preserve alignment + * in structures using it. + */ + /* uint8_t field_array[0]; */ /* Zero or more fields encoded as + * OXM TLVs where the has_mask bit must + * be zero and the value it specifies is + * a mask to apply to packet fields and + * then input them to the selection + * method of a select group. */ + /* uint8_t pad2[0]; */ +}; +OFP_ASSERT(sizeof(struct ntr_group_prop_selection_method) == 40); + +#endif /* openflow/netronome-ext.h */ -- cgit v1.2.1 From bc65c25ac604d5787714c8f16c8df8e392e8dae9 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Fri, 20 Mar 2015 13:50:30 +0900 Subject: Support decoding of NTR selection method This is in preparation for supporting group mod and desc reply messages with an NTR selection method group experimenter property. Currently decoding always fails as it only allows properties for known selection methods and no selection methods are known yet. A subsequent patch will propose a hash selection method. NTR selection method Signed-off-by: Simon Horman Signed-off-by: Ben Pfaff --- lib/meta-flow.c | 9 ++ lib/meta-flow.h | 10 ++ lib/nx-match.c | 46 +++++++++ lib/nx-match.h | 2 + lib/ofp-util.c | 249 +++++++++++++++++++++++++++++++++++++++++++-- lib/ofp-util.h | 15 +++ ofproto/ofproto-provider.h | 2 + ofproto/ofproto.c | 3 + 8 files changed, 328 insertions(+), 8 deletions(-) diff --git a/lib/meta-flow.c b/lib/meta-flow.c index 8058e072e..54e7f5806 100644 --- a/lib/meta-flow.c +++ b/lib/meta-flow.c @@ -2278,3 +2278,12 @@ mf_format_subvalue(const union mf_subvalue *subvalue, struct ds *s) } ds_put_char(s, '0'); } + +void +field_array_set(enum mf_field_id id, const union mf_value *value, + struct field_array *fa) +{ + ovs_assert(id < MFF_N_IDS); + bitmap_set1(fa->used.bm, id); + fa->value[id] = *value; +} diff --git a/lib/meta-flow.h b/lib/meta-flow.h index 0e0903693..ba87afff2 100644 --- a/lib/meta-flow.h +++ b/lib/meta-flow.h @@ -1574,6 +1574,12 @@ union mf_subvalue { }; BUILD_ASSERT_DECL(sizeof(union mf_value) == sizeof (union mf_subvalue)); +/* An array of fields with values */ +struct field_array { + struct mf_bitmap used; + union mf_value value[MFF_N_IDS]; +}; + /* Finding mf_fields. */ const struct mf_field *mf_from_name(const char *name); @@ -1652,4 +1658,8 @@ void mf_format(const struct mf_field *, struct ds *); void mf_format_subvalue(const union mf_subvalue *subvalue, struct ds *s); +/* Field Arrays. */ +void field_array_set(enum mf_field_id id, const union mf_value *, + struct field_array *); + #endif /* meta-flow.h */ diff --git a/lib/nx-match.c b/lib/nx-match.c index 721fce526..e27e50f87 100644 --- a/lib/nx-match.c +++ b/lib/nx-match.c @@ -589,6 +589,52 @@ oxm_pull_match_loose(struct ofpbuf *b, struct match *match) { return oxm_pull_match__(b, false, match); } + +/* Verify an array of OXM TLVs treating value of each TLV as a mask, + * disallowing masks in each TLV and ignoring pre-requisites. */ +enum ofperr +oxm_pull_field_array(const void *fields_data, size_t fields_len, + struct field_array *fa) +{ + struct ofpbuf b; + + ofpbuf_use_const(&b, fields_data, fields_len); + while (b.size) { + const uint8_t *pos = b.data; + const struct mf_field *field; + union mf_value value; + enum ofperr error; + uint64_t header; + + error = nx_pull_entry__(&b, false, &header, &field, &value, NULL); + if (error) { + VLOG_DBG_RL(&rl, "error pulling field array field"); + return error; + } else if (!field) { + VLOG_DBG_RL(&rl, "unknown field array field"); + error = OFPERR_OFPBMC_BAD_FIELD; + } else if (bitmap_is_set(fa->used.bm, field->id)) { + VLOG_DBG_RL(&rl, "duplicate field array field '%s'", field->name); + error = OFPERR_OFPBMC_DUP_FIELD; + } else if (!mf_is_mask_valid(field, &value)) { + VLOG_DBG_RL(&rl, "bad mask in field array field '%s'", field->name); + return OFPERR_OFPBMC_BAD_MASK; + } else { + field_array_set(field->id, &value, fa); + } + + if (error) { + const uint8_t *start = fields_data; + + VLOG_DBG_RL(&rl, "error parsing OXM at offset %"PRIdPTR" " + "within field array (%s)", pos - start, + ofperr_to_string(error)); + return error; + } + } + + return 0; +} /* nx_put_match() and helpers. * diff --git a/lib/nx-match.h b/lib/nx-match.h index 9cb64614c..099253645 100644 --- a/lib/nx-match.h +++ b/lib/nx-match.h @@ -55,6 +55,8 @@ enum ofperr nx_pull_match_loose(struct ofpbuf *, unsigned int match_len, ovs_be64 *cookie_mask); enum ofperr oxm_pull_match(struct ofpbuf *, struct match *); enum ofperr oxm_pull_match_loose(struct ofpbuf *, struct match *); +enum ofperr oxm_pull_field_array(const void *, size_t fields_len, + struct field_array *); int nx_put_match(struct ofpbuf *, const struct match *, ovs_be64 cookie, ovs_be64 cookie_mask); int oxm_put_match(struct ofpbuf *, const struct match *, enum ofp_version); diff --git a/lib/ofp-util.c b/lib/ofp-util.c index d5927a9f3..34e6df45b 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -38,6 +38,7 @@ #include "ofp-msgs.h" #include "ofp-util.h" #include "ofpbuf.h" +#include "openflow/netronome-ext.h" #include "packets.h" #include "random.h" #include "unaligned.h" @@ -59,6 +60,14 @@ struct ofp_prop_header { ovs_be16 len; }; +struct ofp_prop_experimenter { + ovs_be16 type; /* OFP*_EXPERIMENTER. */ + ovs_be16 length; /* Length in bytes of this property. */ + ovs_be32 experimenter; /* Experimenter ID which takes the same form as + * in struct ofp_experimenter_header. */ + ovs_be32 exp_type; /* Experimenter defined. */ +}; + /* Pulls a property, beginning with struct ofp_prop_header, from the beginning * of 'msg'. Stores the type of the property in '*typep' and, if 'property' is * nonnull, the entire property, including the header, in '*property'. Returns @@ -7020,6 +7029,13 @@ ofputil_encode_group_stats_request(enum ofp_version ofp_version, return request; } +void +ofputil_uninit_group_desc(struct ofputil_group_desc *gd) +{ + ofputil_bucket_list_destroy(&gd->buckets); + free(&gd->props.fields); +} + /* Decodes the OpenFlow group description request in 'oh', returning the group * whose description is requested, or OFPG_ALL if stats for all groups was * requested. */ @@ -7721,6 +7737,199 @@ ofputil_pull_ofp15_buckets(struct ofpbuf *msg, size_t buckets_length, return 0; } +static void +ofputil_init_group_properties(struct ofputil_group_props *gp) +{ + memset(gp, 0, sizeof *gp); +} + +static enum ofperr +parse_group_prop_ntr_selection_method(struct ofpbuf *payload, + enum ofp11_group_type group_type, + enum ofp15_group_mod_command group_cmd, + struct ofputil_group_props *gp) +{ + struct ntr_group_prop_selection_method *prop = payload->data; + size_t fields_len, method_len; + enum ofperr error; + + switch (group_type) { + case OFPGT11_SELECT: + break; + case OFPGT11_ALL: + case OFPGT11_INDIRECT: + case OFPGT11_FF: + log_property(false, "ntr selection method property is only allowed " + "for select groups"); + return OFPERR_OFPBPC_BAD_VALUE; + default: + OVS_NOT_REACHED(); + } + + switch (group_cmd) { + case OFPGC15_ADD: + case OFPGC15_MODIFY: + break; + case OFPGC15_DELETE: + case OFPGC15_INSERT_BUCKET: + case OFPGC15_REMOVE_BUCKET: + log_property(false, "ntr selection method property is only allowed " + "for add and delete group modifications"); + return OFPERR_OFPBPC_BAD_VALUE; + default: + OVS_NOT_REACHED(); + } + + if (payload->size < sizeof *prop) { + log_property(false, "ntr selection method property length " + "%u is not valid", payload->size); + return OFPERR_OFPBPC_BAD_LEN; + } + + method_len = strnlen(prop->selection_method, NTR_MAX_SELECTION_METHOD_LEN); + + if (method_len == NTR_MAX_SELECTION_METHOD_LEN) { + log_property(false, "ntr selection method is not null terminated"); + return OFPERR_OFPBPC_BAD_VALUE; + } + + /* Only allow selection method property if the selection_method field + * matches a suported method. As no methods are currently supported + * this check is a no-op that always fails. As selection methods are + * added they should be checked against the selection_method field + * here. */ + log_property(false, "ntr selection method '%s' is not supported", + prop->selection_method); + return OFPERR_OFPBPC_BAD_VALUE; + + strcpy(gp->selection_method, prop->selection_method); + gp->selection_method_param = ntohll(prop->selection_method_param); + + if (!method_len && gp->selection_method_param) { + log_property(false, "ntr selection method parameter is non-zero but " + "selection method is empty"); + return OFPERR_OFPBPC_BAD_VALUE; + } + + ofpbuf_pull(payload, sizeof *prop); + + fields_len = ntohs(prop->length) - sizeof *prop; + if (!method_len && fields_len) { + log_property(false, "ntr selection method parameter is zero " + "but fields are provided"); + return OFPERR_OFPBPC_BAD_VALUE; + } + + error = oxm_pull_field_array(payload->data, fields_len, + &gp->fields); + if (error) { + log_property(false, "ntr selection method fields are invalid"); + return error; + } + + return 0; +} + +static enum ofperr +parse_group_prop_ntr(struct ofpbuf *payload, uint32_t exp_type, + enum ofp11_group_type group_type, + enum ofp15_group_mod_command group_cmd, + struct ofputil_group_props *gp) +{ + enum ofperr error; + + switch (exp_type) { + case NTRT_SELECTION_METHOD: + error = parse_group_prop_ntr_selection_method(payload, group_type, + group_cmd, gp); + break; + + default: + log_property(false, "unknown group property ntr experimenter type " + "%"PRIu32, exp_type); + error = OFPERR_OFPBPC_BAD_TYPE; + break; + } + + return error; +} + +static enum ofperr +parse_ofp15_group_prop_exp(struct ofpbuf *payload, + enum ofp11_group_type group_type, + enum ofp15_group_mod_command group_cmd, + struct ofputil_group_props *gp) +{ + struct ofp_prop_experimenter *prop = payload->data; + uint16_t experimenter; + uint32_t exp_type; + enum ofperr error; + + if (payload->size < sizeof *prop) { + return OFPERR_OFPBPC_BAD_LEN; + } + + experimenter = ntohl(prop->experimenter); + exp_type = ntohl(prop->exp_type); + + switch (experimenter) { + case NTR_VENDOR_ID: + error = parse_group_prop_ntr(payload, exp_type, group_type, + group_cmd, gp); + break; + + default: + log_property(false, "unknown group property experimenter %"PRIu16, + experimenter); + error = OFPERR_OFPBPC_BAD_EXPERIMENTER; + break; + } + + return error; +} + +static enum ofperr +parse_ofp15_group_properties(struct ofpbuf *msg, + enum ofp11_group_type group_type, + enum ofp15_group_mod_command group_cmd, + struct ofputil_group_props *gp, + size_t properties_len) +{ + struct ofpbuf properties; + + ofpbuf_use_const(&properties, ofpbuf_pull(msg, properties_len), + properties_len); + + while (properties.size > 0) { + struct ofpbuf payload; + enum ofperr error; + uint16_t type; + + error = ofputil_pull_property(&properties, &payload, &type); + if (error) { + return error; + } + + switch (type) { + case OFPGPT15_EXPERIMENTER: + error = parse_ofp15_group_prop_exp(&payload, group_type, + group_cmd, gp); + break; + + default: + log_property(false, "unknown group property %"PRIu16, type); + error = OFPERR_OFPBPC_BAD_TYPE; + break; + } + + if (error) { + return error; + } + } + + return 0; +} + static int ofputil_decode_ofp11_group_desc_reply(struct ofputil_group_desc *gd, struct ofpbuf *msg, @@ -7764,6 +7973,7 @@ ofputil_decode_ofp15_group_desc_reply(struct ofputil_group_desc *gd, { struct ofp15_group_desc_stats *ogds; uint16_t length, bucket_list_len; + int error; if (!msg->header) { ofpraw_pull_assert(msg); @@ -7795,9 +8005,22 @@ ofputil_decode_ofp15_group_desc_reply(struct ofputil_group_desc *gd, "bucket list length %u", bucket_list_len); return OFPERR_OFPBRC_BAD_LEN; } + error = ofputil_pull_ofp15_buckets(msg, bucket_list_len, version, + &gd->buckets); + if (error) { + return error; + } - return ofputil_pull_ofp15_buckets(msg, bucket_list_len, version, - &gd->buckets); + /* By definition group desc messages don't have a group mod command. + * However, parse_group_prop_ntr_selection_method() checks to make sure + * that the command is OFPGC15_ADD or OFPGC15_DELETE to guard + * against group mod messages with other commands supplying + * a NTR selection method group experimenter property. + * Such properties are valid for group desc replies so + * claim that the group mod command is OFPGC15_ADD to + * satisfy the check in parse_group_prop_ntr_selection_method() */ + return parse_ofp15_group_properties(msg, gd->type, OFPGC15_ADD, &gd->props, + msg->size); } /* Converts a group description reply in 'msg' into an abstract @@ -7814,6 +8037,8 @@ int ofputil_decode_group_desc_reply(struct ofputil_group_desc *gd, struct ofpbuf *msg, enum ofp_version version) { + ofputil_init_group_properties(&gd->props); + switch (version) { case OFP11_VERSION: @@ -7831,6 +8056,12 @@ ofputil_decode_group_desc_reply(struct ofputil_group_desc *gd, } } +void +ofputil_uninit_group_mod(struct ofputil_group_mod *gm) +{ + ofputil_bucket_list_destroy(&gm->buckets); +} + static struct ofpbuf * ofputil_encode_ofp11_group_mod(enum ofp_version ofp_version, const struct ofputil_group_mod *gm) @@ -8064,14 +8295,14 @@ ofputil_pull_ofp15_group_mod(struct ofpbuf *msg, enum ofp_version ofp_version, } bucket_list_len = ntohs(ogm->bucket_array_len); - if (bucket_list_len < msg->size) { - VLOG_WARN_RL(&bad_ofmsg_rl, "group has %u trailing bytes", - msg->size - bucket_list_len); - return OFPERR_OFPGMFC_BAD_BUCKET; + error = ofputil_pull_ofp15_buckets(msg, bucket_list_len, ofp_version, + &gm->buckets); + if (error) { + return error; } - return ofputil_pull_ofp15_buckets(msg, bucket_list_len, ofp_version, - &gm->buckets); + return parse_ofp15_group_properties(msg, gm->type, gm->command, &gm->props, + msg->size); } /* Converts OpenFlow group mod message 'oh' into an abstract group mod in @@ -8088,6 +8319,8 @@ ofputil_decode_group_mod(const struct ofp_header *oh, ofpbuf_use_const(&msg, oh, ntohs(oh->length)); ofpraw_pull_assert(&msg); + ofputil_init_group_properties(&gm->props); + switch (ofp_version) { case OFP11_VERSION: diff --git a/lib/ofp-util.h b/lib/ofp-util.h index df4d04465..ee3f1bed6 100644 --- a/lib/ofp-util.h +++ b/lib/ofp-util.h @@ -27,6 +27,7 @@ #include "match.h" #include "meta-flow.h" #include "netdev.h" +#include "openflow/netronome-ext.h" #include "openflow/nicira-ext.h" #include "openvswitch/types.h" #include "type-props.h" @@ -217,6 +218,8 @@ void ofputil_match_to_ofp10_match(const struct match *, struct ofp10_match *); /* Work with ofp11_match. */ enum ofperr ofputil_pull_ofp11_match(struct ofpbuf *, struct match *, uint16_t *padded_match_len); +enum ofperr ofputil_pull_ofp11_mask(struct ofpbuf *, struct match *, + struct mf_bitmap *bm); enum ofperr ofputil_match_from_ofp11_match(const struct ofp11_match *, struct match *); int ofputil_put_ofp11_match(struct ofpbuf *, const struct match *, @@ -993,6 +996,14 @@ struct ofputil_bucket { struct bucket_counter stats; }; +/* Protocol-independent group_mod. */ +struct ofputil_group_props { + /* NTR selection method */ + char selection_method[NTR_MAX_SELECTION_METHOD_LEN]; + uint64_t selection_method_param; + struct field_array fields; +}; + /* Protocol-independent group_mod. */ struct ofputil_group_mod { uint16_t command; /* One of OFPGC15_*. */ @@ -1003,6 +1014,7 @@ struct ofputil_group_mod { * OFPGC15_REMOVE_BUCKET commands * execution.*/ struct ovs_list buckets; /* Contains "struct ofputil_bucket"s. */ + struct ofputil_group_props props; /* Group properties. */ }; /* Group stats reply, independent of protocol. */ @@ -1032,6 +1044,7 @@ struct ofputil_group_desc { uint8_t type; /* One of OFPGT_*. */ uint32_t group_id; /* Group identifier. */ struct ovs_list buckets; /* Contains "struct ofputil_bucket"s. */ + struct ofputil_group_props props; /* Group properties. */ }; void ofputil_bucket_list_destroy(struct ovs_list *buckets); @@ -1062,6 +1075,7 @@ struct ofpbuf *ofputil_encode_group_features_reply( const struct ofputil_group_features *, const struct ofp_header *request); void ofputil_decode_group_features_reply(const struct ofp_header *, struct ofputil_group_features *); +void ofputil_uninit_group_mod(struct ofputil_group_mod *gm); struct ofpbuf *ofputil_encode_group_mod(enum ofp_version ofp_version, const struct ofputil_group_mod *gm); @@ -1071,6 +1085,7 @@ enum ofperr ofputil_decode_group_mod(const struct ofp_header *, int ofputil_decode_group_stats_reply(struct ofpbuf *, struct ofputil_group_stats *); +void ofputil_uninit_group_desc(struct ofputil_group_desc *gd); uint32_t ofputil_decode_group_desc_request(const struct ofp_header *); struct ofpbuf *ofputil_encode_group_desc_request(enum ofp_version, uint32_t group_id); diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h index 7208541b1..9222fe431 100644 --- a/ofproto/ofproto-provider.h +++ b/ofproto/ofproto-provider.h @@ -499,6 +499,8 @@ struct ofgroup { struct ovs_list buckets; /* Contains "struct ofputil_bucket"s. */ const uint32_t n_buckets; + + const struct ofputil_group_props props; }; bool ofproto_group_lookup(const struct ofproto *ofproto, uint32_t group_id, diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 07a1f5d5d..ff1632fef 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -5929,6 +5929,9 @@ init_group(struct ofproto *ofproto, struct ofputil_group_mod *gm, *CONST_CAST(uint32_t *, &(*ofgroup)->n_buckets) = list_size(&(*ofgroup)->buckets); + memcpy(CONST_CAST(struct ofputil_group_props *, &(*ofgroup)->props), + &gm->props, sizeof (struct ofputil_group_props)); + /* Construct called BEFORE any locks are held. */ error = ofproto->ofproto_class->group_construct(*ofgroup); if (error) { -- cgit v1.2.1 From 53eb84a52cbd8ff279a32f3e7fc2c51e608e5e7a Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Fri, 20 Mar 2015 13:50:31 +0900 Subject: Support encoding of NTR selection method Include NTR selection method experimenter group property in in group mod request and group desc reply. NTR selection method Signed-off-by: Simon Horman Signed-off-by: Ben Pfaff --- lib/nx-match.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/nx-match.h | 3 +++ lib/ofp-print.c | 32 ++++++++++++++++++----- lib/ofp-util.c | 31 ++++++++++++++++++++++ ofproto/ofproto.c | 2 ++ 5 files changed, 140 insertions(+), 6 deletions(-) diff --git a/lib/nx-match.c b/lib/nx-match.c index e27e50f87..4b724604f 100644 --- a/lib/nx-match.c +++ b/lib/nx-match.c @@ -1067,6 +1067,84 @@ oxm_put_match(struct ofpbuf *b, const struct match *match, return match_len; } +/* Appends to 'b' the nx_match format that expresses the tlv corresponding + * to 'id'. If mask is not all-ones then it is also formated as the value + * of the tlv. */ +static void +nx_format_mask_tlv(struct ds *ds, enum mf_field_id id, + const union mf_value *mask) +{ + const struct mf_field *mf = mf_from_id(id); + + ds_put_format(ds, "%s", mf->name); + + if (!is_all_ones(mask, mf->n_bytes)) { + ds_put_char(ds, '='); + mf_format(mf, mask, NULL, ds); + } + + ds_put_char(ds, ','); +} + +/* Appends a string representation of 'fa_' to 'ds'. + * The TLVS value of 'fa_' is treated as a mask and + * only the name of fields is formated if it is all ones. */ +void +oxm_format_field_array(struct ds *ds, const struct field_array *fa) +{ + size_t start_len = ds->length; + int i; + + for (i = 0; i < MFF_N_IDS; i++) { + if (bitmap_is_set(fa->used.bm, i)) { + nx_format_mask_tlv(ds, i, &fa->value[i]); + } + } + + if (ds->length > start_len) { + ds_chomp(ds, ','); + } +} + +/* Appends to 'b' a series of OXM TLVs corresponding to the series + * of enum mf_field_id and value tuples in 'fa_'. + * + * OXM differs slightly among versions of OpenFlow. Specify the OpenFlow + * version in use as 'version'. + * + * This function can cause 'b''s data to be reallocated. + * + * Returns the number of bytes appended to 'b'. May return zero. */ +int +oxm_put_field_array(struct ofpbuf *b, const struct field_array *fa, + enum ofp_version version) +{ + size_t start_len = b->size; + int i; + + /* Field arrays are only used with the group selection method + * property and group properties are only available in OpenFlow * 1.5+. + * So the following assertion should never fail. + * + * If support for older OpenFlow versions is desired then some care + * will need to be taken of different TLVs that handle the same + * flow fields. In particular: + * - VLAN_TCI, VLAN_VID and MFF_VLAN_PCP + * - IP_DSCP_MASK and DSCP_SHIFTED + * - REGS and XREGS + */ + ovs_assert(version >= OFP15_VERSION); + + for (i = 0; i < MFF_N_IDS; i++) { + if (bitmap_is_set(fa->used.bm, i)) { + nxm_put_unmasked(b, i, version, &fa->value[i], + mf_from_id(i)->n_bytes); + } + } + + return b->size - start_len; +} + static void nx_put_header__(struct ofpbuf *b, uint64_t header, bool masked) { diff --git a/lib/nx-match.h b/lib/nx-match.h index 099253645..fe0b68c56 100644 --- a/lib/nx-match.h +++ b/lib/nx-match.h @@ -60,6 +60,9 @@ enum ofperr oxm_pull_field_array(const void *, size_t fields_len, int nx_put_match(struct ofpbuf *, const struct match *, ovs_be64 cookie, ovs_be64 cookie_mask); int oxm_put_match(struct ofpbuf *, const struct match *, enum ofp_version); +void oxm_format_field_array(struct ds *, const struct field_array *); +int oxm_put_field_array(struct ofpbuf *, const struct field_array *, + enum ofp_version version); /* Decoding and encoding OXM/NXM headers (just a field ID) or entries (a field * ID followed by a value and possibly a mask). */ diff --git a/lib/ofp-print.c b/lib/ofp-print.c index b7c9a2641..cec074f1e 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -2156,8 +2156,8 @@ ofp_print_bucket_id(struct ds *s, const char *label, uint32_t bucket_id, static void ofp_print_group(struct ds *s, uint32_t group_id, uint8_t type, - struct ovs_list *p_buckets, enum ofp_version ofp_version, - bool suppress_type) + struct ovs_list *p_buckets, struct ofputil_group_props *props, + enum ofp_version ofp_version, bool suppress_type) { struct ofputil_bucket *bucket; @@ -2169,6 +2169,26 @@ ofp_print_group(struct ds *s, uint32_t group_id, uint8_t type, ds_put_format(s, ",type=%s", type_str[type > 4 ? 4 : type]); } + if (props->selection_method[0]) { + size_t mark, start; + + ds_put_format(s, ",selection_method=%s,", props->selection_method); + if (props->selection_method_param) { + ds_put_format(s, "selection_method_param=%"PRIu64",", + props->selection_method_param); + } + + /* Allow rewinding to immediately before the trailing ',' */ + mark = s->length - 1; + + ds_put_cstr(s, "fields="); + start = s->length; + oxm_format_field_array(s, &props->fields); + if (s->length == start) { + ds_truncate(s, mark); + } + } + if (!p_buckets) { return; } @@ -2226,8 +2246,8 @@ ofp_print_group_desc(struct ds *s, const struct ofp_header *oh) ds_put_char(s, '\n'); ds_put_char(s, ' '); - ofp_print_group(s, gd.group_id, gd.type, &gd.buckets, oh->version, - false); + ofp_print_group(s, gd.group_id, gd.type, &gd.buckets, &gd.props, + oh->version, false); ofputil_bucket_list_destroy(&gd.buckets); } } @@ -2380,8 +2400,8 @@ ofp_print_group_mod(struct ds *s, const struct ofp_header *oh) gm.command_bucket_id, oh->version); } - ofp_print_group(s, gm.group_id, gm.type, &gm.buckets, oh->version, - bucket_command); + ofp_print_group(s, gm.group_id, gm.type, &gm.buckets, &gm.props, + oh->version, bucket_command); ofputil_bucket_list_destroy(&gm.buckets); } diff --git a/lib/ofp-util.c b/lib/ofp-util.c index 34e6df45b..7b68564e8 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -7427,6 +7427,26 @@ ofputil_put_ofp15_bucket(const struct ofputil_bucket *bucket, ob->bucket_id = htonl(bucket_id); } +static void +ofputil_put_group_prop_ntr_selection_method(enum ofp_version ofp_version, + const struct ofputil_group_props *gp, + struct ofpbuf *openflow) +{ + struct ntr_group_prop_selection_method *prop; + size_t start; + + start = openflow->size; + ofpbuf_put_zeros(openflow, sizeof *prop); + oxm_put_field_array(openflow, &gp->fields, ofp_version); + prop = ofpbuf_at_assert(openflow, start, sizeof *prop); + prop->type = htons(OFPGPT15_EXPERIMENTER); + prop->experimenter = htonl(NTR_VENDOR_ID); + prop->exp_type = htonl(NTRT_SELECTION_METHOD); + strcpy(prop->selection_method, gp->selection_method); + prop->selection_method_param = htonll(gp->selection_method_param); + end_property(openflow, start); +} + static void ofputil_append_ofp11_group_desc_reply(const struct ofputil_group_desc *gds, const struct ovs_list *buckets, @@ -7475,6 +7495,12 @@ ofputil_append_ofp15_group_desc_reply(const struct ofputil_group_desc *gds, ogds->group_id = htonl(gds->group_id); ogds->bucket_list_len = htons(reply->size - start_buckets); + /* Add group properties */ + if (gds->props.selection_method[0]) { + ofputil_put_group_prop_ntr_selection_method(version, &gds->props, + reply); + } + ofpmp_postappend(replies, start_ogds); } @@ -8138,6 +8164,11 @@ ofputil_encode_ofp15_group_mod(enum ofp_version ofp_version, ogm->command_bucket_id = htonl(gm->command_bucket_id); ogm->bucket_array_len = htons(b->size - start_ogm - sizeof *ogm); + /* Add group properties */ + if (gm->props.selection_method[0]) { + ofputil_put_group_prop_ntr_selection_method(ofp_version, &gm->props, b); + } + id_pool_destroy(bucket_ids); return b; } diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index ff1632fef..a36a1f8cc 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -5827,6 +5827,8 @@ append_group_desc(struct ofgroup *group, struct ovs_list *replies) gds.group_id = group->group_id; gds.type = group->type; + gds.props = group->props; + ofputil_append_group_desc_reply(&gds, &group->buckets, replies); } -- cgit v1.2.1 From 7565c3e4fe1f98f5eb1a4b2151ef3d22ceb37b00 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Fri, 20 Mar 2015 13:50:32 +0900 Subject: Support translation of NTR selection method Only the default existing behaviour is translated. All other methods are rejected for now. NTR selection method Signed-off-by: Simon Horman Signed-off-by: Ben Pfaff --- ofproto/ofproto-dpif-xlate.c | 15 ++++++++++++++- ofproto/ofproto-dpif.c | 6 ++++++ ofproto/ofproto-dpif.h | 1 + 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index 0e28c777f..75d3eed11 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -3092,7 +3092,7 @@ xlate_ff_group(struct xlate_ctx *ctx, struct group_dpif *group) } static void -xlate_select_group(struct xlate_ctx *ctx, struct group_dpif *group) +xlate_default_select_group(struct xlate_ctx *ctx, struct group_dpif *group) { struct flow_wildcards *wc = &ctx->xout->wc; struct ofputil_bucket *bucket; @@ -3116,6 +3116,19 @@ xlate_select_group(struct xlate_ctx *ctx, struct group_dpif *group) } } +static void +xlate_select_group(struct xlate_ctx *ctx, struct group_dpif *group) +{ + const char *selection_method = group_dpif_get_selection_method(group); + + if (selection_method[0] == '\0') { + xlate_default_select_group(ctx, group); + } else { + /* Parsing of groups should ensure this never happens */ + OVS_NOT_REACHED(); + } +} + static void xlate_group_action__(struct xlate_ctx *ctx, struct group_dpif *group) { diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 38ad6e253..43a21c239 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -4241,6 +4241,12 @@ group_dpif_get_type(const struct group_dpif *group) { return group->up.type; } + +const char * +group_dpif_get_selection_method(const struct group_dpif *group) +{ + return group->up.props.selection_method; +} /* Sends 'packet' out 'ofport'. * May modify 'packet'. diff --git a/ofproto/ofproto-dpif.h b/ofproto/ofproto-dpif.h index e2359cd06..fd099a24d 100644 --- a/ofproto/ofproto-dpif.h +++ b/ofproto/ofproto-dpif.h @@ -137,6 +137,7 @@ bool group_dpif_lookup(struct ofproto_dpif *ofproto, uint32_t group_id, void group_dpif_get_buckets(const struct group_dpif *group, const struct ovs_list **buckets); enum ofp11_group_type group_dpif_get_type(const struct group_dpif *group); +const char *group_dpif_get_selection_method(const struct group_dpif *group); bool ofproto_has_vlan_splinters(const struct ofproto_dpif *); ofp_port_t vsp_realdev_to_vlandev(const struct ofproto_dpif *, -- cgit v1.2.1 From b879391e0f2fed8e52ae20ad21ad8ae52cea8363 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Fri, 20 Mar 2015 13:50:33 +0900 Subject: Support NTR selection method in ovs-ofctl group commands NTR selection method Signed-off-by: Simon Horman Signed-off-by: Ben Pfaff --- lib/ofp-parse.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++ tests/ofproto.at | 4 +-- utilities/ovs-ofctl.8.in | 34 ++++++++++++++++++ 3 files changed, 130 insertions(+), 2 deletions(-) diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c index 8d05681d6..8fce546f4 100644 --- a/lib/ofp-parse.c +++ b/lib/ofp-parse.c @@ -1157,6 +1157,67 @@ parse_bucket_str(struct ofputil_bucket *bucket, char *str_, return NULL; } +static char * OVS_WARN_UNUSED_RESULT +parse_select_group_field(char *s, struct field_array *fa, + enum ofputil_protocol *usable_protocols) +{ + char *save_ptr = NULL; + char *name; + + for (name = strtok_r(s, "=, \t\r\n", &save_ptr); name; + name = strtok_r(NULL, "=, \t\r\n", &save_ptr)) { + const struct mf_field *mf = mf_from_name(name); + + if (mf) { + char *error; + const char *value_str; + union mf_value value; + + if (bitmap_is_set(fa->used.bm, mf->id)) { + return xasprintf("%s: duplicate field", name); + } + + value_str = strtok_r(NULL, ", \t\r\n", &save_ptr); + if (value_str) { + error = mf_parse_value(mf, value_str, &value); + if (error) { + return error; + } + + /* The mask cannot be all-zeros */ + if (is_all_zeros(&value, mf->n_bytes)) { + return xasprintf("%s: values are wildcards here " + "and must not be all-zeros", s); + } + + /* The values parsed are masks for fields used + * by the selection method */ + if (!mf_is_mask_valid(mf, &value)) { + return xasprintf("%s: invalid mask for field %s", + value_str, mf->name); + } + } else { + memset(&value, 0xff, mf->n_bytes); + } + + field_array_set(mf->id, &value, fa); + + if (is_all_ones(&value, mf->n_bytes)) { + *usable_protocols &= mf->usable_protocols_exact; + } else if (mf->usable_protocols_bitwise == mf->usable_protocols_cidr + || ip_is_cidr(value.be32)) { + *usable_protocols &= mf->usable_protocols_cidr; + } else { + *usable_protocols &= mf->usable_protocols_bitwise; + } + } else { + return xasprintf("%s: unknown field %s", s, name); + } + } + + return NULL; +} + static char * OVS_WARN_UNUSED_RESULT parse_ofp_group_mod_str__(struct ofputil_group_mod *gm, uint16_t command, char *string, @@ -1327,6 +1388,39 @@ parse_ofp_group_mod_str__(struct ofputil_group_mod *gm, uint16_t command, } else if (!strcmp(name, "bucket")) { error = xstrdup("bucket is not needed"); goto out; + } else if (!strcmp(name, "selection_method")) { + if (!(fields & F_GROUP_TYPE)) { + error = xstrdup("selection method is not needed"); + goto out; + } + if (strlen(value) >= NTR_MAX_SELECTION_METHOD_LEN) { + error = xasprintf("selection method is longer than %u" + " bytes long", + NTR_MAX_SELECTION_METHOD_LEN - 1); + goto out; + } + memset(gm->props.selection_method, '\0', + NTR_MAX_SELECTION_METHOD_LEN); + strcpy(gm->props.selection_method, value); + *usable_protocols &= OFPUTIL_P_OF15_UP; + } else if (!strcmp(name, "selection_method_param")) { + if (!(fields & F_GROUP_TYPE)) { + error = xstrdup("selection method param is not needed"); + goto out; + } + error = str_to_u64(value, &gm->props.selection_method_param); + *usable_protocols &= OFPUTIL_P_OF15_UP; + } else if (!strcmp(name, "fields")) { + if (!(fields & F_GROUP_TYPE)) { + error = xstrdup("fields are not needed"); + goto out; + } + error = parse_select_group_field(value, &gm->props.fields, + usable_protocols); + if (error) { + goto out; + } + *usable_protocols &= OFPUTIL_P_OF15_UP; } else { error = xasprintf("unknown keyword %s", name); goto out; diff --git a/tests/ofproto.at b/tests/ofproto.at index a3f5e2a1d..62629c099 100644 --- a/tests/ofproto.at +++ b/tests/ofproto.at @@ -338,14 +338,14 @@ dnl Actions definition listed in both supported formats (w/ actions=) AT_SETUP([ofproto - del group (OpenFlow 1.5)]) OVS_VSWITCHD_START AT_DATA([groups.txt], [dnl -group_id=1234,type=all,bucket=output:10,bucket=output:11 +group_id=1234,type=select,selection_method=hash,bucket=output:10,bucket=output:11 group_id=1235,type=all,bucket=actions=output:12,bucket=bucket_id:0,actions=output:10,bucket=bucket_id:1,actions=output:11 ]) AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn add-groups br0 groups.txt]) AT_CHECK([ovs-ofctl -F OXM-OpenFlow15 -O OpenFlow15 -vwarn dump-groups br0 1234], [0], [stdout]) AT_CHECK([STRIP_XIDS stdout], [0], [dnl OFPST_GROUP_DESC reply (OF1.5): - group_id=1234,type=all,bucket=bucket_id:0,actions=output:10,bucket=bucket_id:1,actions=output:11 + group_id=1234,type=select,selection_method=hash,bucket=bucket_id:0,actions=output:10,bucket=bucket_id:1,actions=output:11 ]) AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn del-groups br0 group_id=1234]) AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn dump-groups br0], [0], [stdout]) diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in index 7aee788b0..ea3337b93 100644 --- a/utilities/ovs-ofctl.8.in +++ b/utilities/ovs-ofctl.8.in @@ -2248,6 +2248,40 @@ remove the in the group whose \fBbucket_id\fR is \fIid\fR. It is an error if there is no bucket persent group in whose \fBbucket_id\fR is \fIid\fR. +.IP \fBselection_method\fR=\fImethod\fR +The selection method used to select a bucket for a select group. +This is a string of 1 to 15 bytes in length known to lower layers. +This field is optional for \fBadd\-group\fR, \fBadd\-groups\fR and +\fBmod\-group\fR commands on groups of type \fBselect\fR. Prohibited +otherwise. The default value is the empty string. +.IP +This option will use a Netronome OpenFlow extension which is only supported +when using Open vSwitch 2.4 and later with OpenFlow 1.5 and later. + +.IP \fBselection_method_param\fR=\fIparam\fR +64-bit integer parameter to the selection method selected by the +\fBselection_method\fR field. The parameter's use is defined by the +lower-layer that implements the \fBselection_method\fR. It is optional if +the \fBselection_method\fR field is specified as a non-empty string. +Prohibited otherwise. The default value is zero. +.IP +This option will use a Netronome OpenFlow extension which is only supported +when using Open vSwitch 2.4 and later with OpenFlow 1.5 and later. + +.IP \fBfields\fR=\fIparam\fR +The field parameters to selection method selected by the +\fBselection_method\fR field. The syntax is described in \fBFlow Syntax\fR +with the additional restrictions that if a value is provided it is +treated as a wildcard mask and wildcard masks following a slash are +prohibited. The pre-requisites of fields must be provided by any flows that +output to the group. The use of the fields is defined by the lower-layer +that implements the \fBselection_method\fR. They are optional if the +\fBselection_method\fR field is specified as a non-empty string. +Prohibited otherwise. The default is no fields. +.IP +This option will use a Netronome OpenFlow extension which is only supported +when using Open vSwitch 2.4 and later with OpenFlow 1.5 and later. + .IP \fBbucket\fR=\fIbucket_parameters\fR The \fBadd-group\fR, \fBadd-groups\fR and \fBmod-group\fR commands require at least one bucket field. Bucket fields must appear after -- cgit v1.2.1 From 0c4b9393b6a5792b888d4b580e04cc3fa64ebc12 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Fri, 20 Mar 2015 13:50:34 +0900 Subject: Implement hash fields select group This is intended as a usable demonstration of how the NTR selection method extension might may be used. NTR selection method Signed-off-by: Simon Horman [blp@nicira.com added a NEWS entry] Signed-off-by: Ben Pfaff --- NEWS | 3 ++ lib/meta-flow.c | 35 +++++++++++++++++++++++ lib/meta-flow.h | 2 ++ lib/ofp-util.c | 13 ++++----- ofproto/ofproto-dpif-xlate.c | 67 ++++++++++++++++++++++++++++++++++++++++++++ ofproto/ofproto-dpif.c | 12 ++++++++ ofproto/ofproto-dpif.h | 2 ++ tests/ofp-print.at | 16 ++++++++--- tests/ofproto-dpif.at | 33 ++++++++++++++++++++++ 9 files changed, 171 insertions(+), 12 deletions(-) diff --git a/NEWS b/NEWS index 79b3703d6..b8ddc19f3 100644 --- a/NEWS +++ b/NEWS @@ -38,6 +38,9 @@ Post-v2.3.0 is executed last, and only if the action set has no "output" or "group" action. * OpenFlow 1.4+ flow "importance" is now maintained in the flow table. + * A new Netronome extension to OpenFlow 1.5+ allows control over the + fields hashed for OpenFlow select groups. See "selection_method" and + related options in ovs-ofctl(8) for details. - ovs-pki: Changed message digest algorithm from MD5 to SHA-1 because MD5 is no longer secure and some operating systems have started to disable it in OpenSSL. diff --git a/lib/meta-flow.c b/lib/meta-flow.c index 54e7f5806..124b5256c 100644 --- a/lib/meta-flow.c +++ b/lib/meta-flow.c @@ -352,6 +352,41 @@ mf_mask_field_and_prereqs(const struct mf_field *mf, struct flow *mask) } } +/* Set bits of 'bm' corresponding to the field 'mf' and it's prerequisities. */ +void +mf_bitmap_set_field_and_prereqs(const struct mf_field *mf, struct mf_bitmap *bm) +{ + bitmap_set1(bm->bm, mf->id); + + switch (mf->prereqs) { + case MFP_ND: + case MFP_ND_SOLICIT: + case MFP_ND_ADVERT: + bitmap_set1(bm->bm, MFF_TCP_SRC); + bitmap_set1(bm->bm, MFF_TCP_DST); + /* Fall through. */ + case MFP_TCP: + case MFP_UDP: + case MFP_SCTP: + case MFP_ICMPV4: + case MFP_ICMPV6: + /* nw_frag always unwildcarded. */ + bitmap_set1(bm->bm, MFF_IP_PROTO); + /* Fall through. */ + case MFP_ARP: + case MFP_IPV4: + case MFP_IPV6: + case MFP_MPLS: + case MFP_IP_ANY: + bitmap_set1(bm->bm, MFF_ETH_TYPE); + break; + case MFP_VLAN_VID: + bitmap_set1(bm->bm, MFF_VLAN_TCI); + break; + case MFP_NONE: + break; + } +} /* Returns true if 'value' may be a valid value *as part of a masked match*, * false otherwise. diff --git a/lib/meta-flow.h b/lib/meta-flow.h index ba87afff2..265f0669f 100644 --- a/lib/meta-flow.h +++ b/lib/meta-flow.h @@ -1601,6 +1601,8 @@ void mf_get_mask(const struct mf_field *, const struct flow_wildcards *, /* Prerequisites. */ bool mf_are_prereqs_ok(const struct mf_field *, const struct flow *); void mf_mask_field_and_prereqs(const struct mf_field *, struct flow *mask); +void mf_bitmap_set_field_and_prereqs(const struct mf_field *mf, struct + mf_bitmap *bm); static inline bool mf_is_l3_or_higher(const struct mf_field *mf) diff --git a/lib/ofp-util.c b/lib/ofp-util.c index 7b68564e8..a0da289d0 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -7819,14 +7819,11 @@ parse_group_prop_ntr_selection_method(struct ofpbuf *payload, return OFPERR_OFPBPC_BAD_VALUE; } - /* Only allow selection method property if the selection_method field - * matches a suported method. As no methods are currently supported - * this check is a no-op that always fails. As selection methods are - * added they should be checked against the selection_method field - * here. */ - log_property(false, "ntr selection method '%s' is not supported", - prop->selection_method); - return OFPERR_OFPBPC_BAD_VALUE; + if (strcmp("hash", prop->selection_method)) { + log_property(false, "ntr selection method '%s' is not supported", + prop->selection_method); + return OFPERR_OFPBPC_BAD_VALUE; + } strcpy(gp->selection_method, prop->selection_method); gp->selection_method_param = ntohll(prop->selection_method_param); diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index 75d3eed11..a7cfe06ac 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -3116,6 +3116,71 @@ xlate_default_select_group(struct xlate_ctx *ctx, struct group_dpif *group) } } +static void +xlate_hash_fields_select_group(struct xlate_ctx *ctx, struct group_dpif *group) +{ + struct mf_bitmap hash_fields = MF_BITMAP_INITIALIZER; + struct flow_wildcards *wc = &ctx->xout->wc; + const struct field_array *fields; + struct ofputil_bucket *bucket; + uint32_t basis; + int i; + + fields = group_dpif_get_fields(group); + basis = hash_uint64(group_dpif_get_selection_method_param(group)); + + /* Determine which fields to hash */ + for (i = 0; i < MFF_N_IDS; i++) { + if (bitmap_is_set(fields->used.bm, i)) { + const struct mf_field *mf; + + /* If the field is already present in 'hash_fields' then + * this loop has already checked that it and its pre-requisites + * are present in the flow and its pre-requisites have + * already been added to 'hash_fields'. There is nothing more + * to do here and as an optimisation the loop can continue. */ + if (bitmap_is_set(hash_fields.bm, i)) { + continue; + } + + mf = mf_from_id(i); + + /* Only hash a field if it and its pre-requisites are present + * in the flow. */ + if (!mf_are_prereqs_ok(mf, &ctx->xin->flow)) { + continue; + } + + /* Hash both the field and its pre-requisites */ + mf_bitmap_set_field_and_prereqs(mf, &hash_fields); + } + } + + /* Hash the fields */ + for (i = 0; i < MFF_N_IDS; i++) { + if (bitmap_is_set(hash_fields.bm, i)) { + const struct mf_field *mf = mf_from_id(i); + union mf_value value; + int j; + + mf_get_value(mf, &ctx->xin->flow, &value); + /* This seems inefficient but so does apply_mask() */ + for (j = 0; j < mf->n_bytes; j++) { + ((uint8_t *) &value)[j] &= ((uint8_t *) &fields->value[i])[j]; + } + basis = hash_bytes(&value, mf->n_bytes, basis); + + mf_mask_field(mf, &wc->masks); + } + } + + bucket = group_best_live_bucket(ctx, group, basis); + if (bucket) { + xlate_group_bucket(ctx, bucket); + xlate_group_stats(ctx, group, bucket); + } +} + static void xlate_select_group(struct xlate_ctx *ctx, struct group_dpif *group) { @@ -3123,6 +3188,8 @@ xlate_select_group(struct xlate_ctx *ctx, struct group_dpif *group) if (selection_method[0] == '\0') { xlate_default_select_group(ctx, group); + } else if (!strcasecmp("hash", selection_method)) { + xlate_hash_fields_select_group(ctx, group); } else { /* Parsing of groups should ensure this never happens */ OVS_NOT_REACHED(); diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 43a21c239..d6a4d8ccb 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -4265,6 +4265,18 @@ ofproto_dpif_send_packet(const struct ofport_dpif *ofport, struct dp_packet *pac ovs_mutex_unlock(&ofproto->stats_mutex); return error; } + +uint64_t +group_dpif_get_selection_method_param(const struct group_dpif *group) +{ + return group->up.props.selection_method_param; +} + +const struct field_array * +group_dpif_get_fields(const struct group_dpif *group) +{ + return &group->up.props.fields; +} /* Return the version string of the datapath that backs up * this 'ofproto'. diff --git a/ofproto/ofproto-dpif.h b/ofproto/ofproto-dpif.h index fd099a24d..19c91f0a0 100644 --- a/ofproto/ofproto-dpif.h +++ b/ofproto/ofproto-dpif.h @@ -138,6 +138,8 @@ void group_dpif_get_buckets(const struct group_dpif *group, const struct ovs_list **buckets); enum ofp11_group_type group_dpif_get_type(const struct group_dpif *group); const char *group_dpif_get_selection_method(const struct group_dpif *group); +uint64_t group_dpif_get_selection_method_param(const struct group_dpif *group); +const struct field_array *group_dpif_get_fields(const struct group_dpif *group); bool ofproto_has_vlan_splinters(const struct ofproto_dpif *); ofp_port_t vsp_realdev_to_vlandev(const struct ofproto_dpif *, diff --git a/tests/ofp-print.at b/tests/ofp-print.at index dc809e252..2bef3fae3 100644 --- a/tests/ofp-print.at +++ b/tests/ofp-print.at @@ -2026,7 +2026,7 @@ AT_CLEANUP AT_SETUP([OFPST_GROUP_DESC reply - OF1.5]) AT_KEYWORDS([ofp-print OFPT_STATS_REPLY]) AT_CHECK([ovs-ofctl ofp-print "\ -06 13 00 98 00 00 00 02 00 07 00 00 00 00 00 00 \ +06 13 00 d8 00 00 00 02 00 07 00 00 00 00 00 00 \ 00 88 01 00 00 00 20 00 00 78 00 00 00 00 00 00 \ 00 28 00 10 00 00 00 00 00 00 00 10 00 00 00 01 \ 00 00 00 00 00 00 00 00 00 00 00 08 00 64 00 00 \ @@ -2037,9 +2037,14 @@ AT_CHECK([ovs-ofctl ofp-print "\ 00 28 00 10 00 00 00 02 00 00 00 10 00 00 00 03 \ 00 00 00 00 00 00 00 00 00 00 00 08 00 c8 00 00 \ 00 01 00 08 00 00 00 03 \ +ff ff 00 3b 00 00 15 40 00 00 00 01 00 00 00 00 \ +68 61 73 68 00 00 00 00 00 00 00 00 00 00 00 00 \ +00 00 00 00 00 00 00 00 \ +80 00 18 04 ff ff ff 00 80 00 1a 02 ff ff 80 00 \ +14 01 ff 00 00 00 00 00 \ "], [0], [dnl OFPST_GROUP_DESC reply (OF1.5) (xid=0x2): - group_id=8192,type=select,bucket=bucket_id:0,weight:100,watch_port:1,actions=output:1,bucket=bucket_id:1,weight:200,watch_port:2,actions=output:2,bucket=bucket_id:2,weight:200,watch_port:3,actions=output:3 + group_id=8192,type=select,selection_method=hash,fields=ip_dst=255.255.255.0,nw_proto,tcp_src,bucket=bucket_id:0,weight:100,watch_port:1,actions=output:1,bucket=bucket_id:1,weight:200,watch_port:2,actions=output:2,bucket=bucket_id:2,weight:200,watch_port:3,actions=output:3 ]) AT_CLEANUP @@ -2845,7 +2850,7 @@ AT_CLEANUP AT_SETUP([OFPT_GROUP_MOD add - OF1.5]) AT_KEYWORDS([ofp-print]) AT_CHECK([ovs-ofctl ofp-print "\ -06 0f 00 90 11 22 33 44 00 00 01 00 87 65 43 21 \ +06 0f 00 b8 11 22 33 44 00 00 01 00 87 65 43 21 \ 00 78 00 00 ff ff ff ff 00 28 00 10 00 00 00 00 \ 00 00 00 10 00 00 00 01 00 00 00 00 00 00 00 00 \ 00 00 00 08 00 64 00 00 00 01 00 08 00 00 00 01 \ @@ -2854,9 +2859,12 @@ AT_CHECK([ovs-ofctl ofp-print "\ 00 01 00 08 00 00 00 02 00 28 00 10 00 00 00 02 \ 00 00 00 10 00 00 00 03 00 00 00 00 00 00 00 00 \ 00 00 00 08 00 c8 00 00 00 01 00 08 00 00 00 03 \ +ff ff 00 28 00 00 15 40 00 00 00 01 00 00 00 00 \ +68 61 73 68 00 00 00 00 00 00 00 00 00 00 00 00 \ +00 00 00 00 00 00 00 07 \ "], [0], [dnl OFPT_GROUP_MOD (OF1.5) (xid=0x11223344): - ADD group_id=2271560481,type=select,bucket=bucket_id:0,weight:100,watch_port:1,actions=output:1,bucket=bucket_id:1,weight:200,watch_port:2,actions=output:2,bucket=bucket_id:2,weight:200,watch_port:3,actions=output:3 + ADD group_id=2271560481,type=select,selection_method=hash,selection_method_param=7,bucket=bucket_id:0,weight:100,watch_port:1,actions=output:1,bucket=bucket_id:1,weight:200,watch_port:2,actions=output:2,bucket=bucket_id:2,weight:200,watch_port:3,actions=output:3 ]) AT_CLEANUP diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at index 897df4e62..575217515 100644 --- a/tests/ofproto-dpif.at +++ b/tests/ofproto-dpif.at @@ -403,6 +403,39 @@ AT_CHECK([tail -1 stdout], [0], OVS_VSWITCHD_STOP AT_CLEANUP +AT_SETUP([ofproto-dpif - select group with hash selection method]) +OVS_VSWITCHD_START +ADD_OF_PORTS([br0], [1], [10], [11]) +AT_CHECK([ovs-ofctl -O OpenFlow15 add-group br0 'group_id=1234,type=select,selection_method=hash,fields=eth_dst,bucket=output:10,bucket=output:11']) +AT_CHECK([ovs-ofctl -O OpenFlow15 add-flow br0 'ip actions=write_actions(group:1234)']) + +# Try a bunch of different flows and make sure that they get distributed +# at least somewhat. +for d in 0 1 2 3 4 5 6 7 8 9 a b c d e f; do + AT_CHECK([ovs-appctl ofproto/trace br0 "in_port=1,dl_src=50:54:00:00:00:07,dl_dst=50:54:00:00:00:0$d,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=1,nw_tos=0,nw_ttl=128,icmp_type=8,icmp_code=0"], [0], [stdout]) + tail -1 stdout >> results +done +sort results | uniq -c +AT_CHECK([sort results | uniq], [0], + [Datapath actions: 10 +Datapath actions: 11 +]) + +> results +# Try a bunch of different flows and make sure that they are not distributed +# as they only vary a field that is not hashed +for d in 0 1 2 3 4 5 6 7 8 9 a b c d e f; do + AT_CHECK([ovs-appctl ofproto/trace br0 "in_port=1,dl_src=50:54:00:00:00:$d,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=1,nw_tos=0,nw_ttl=128,icmp_type=8,icmp_code=0"], [0], [stdout]) + tail -1 stdout >> results +done +sort results | uniq -c +AT_CHECK([sort results | uniq], [0], + [Datapath actions: 10 +]) + +OVS_VSWITCHD_STOP +AT_CLEANUP + AT_SETUP([ofproto-dpif - fast failover group]) OVS_VSWITCHD_START ADD_OF_PORTS([br0], [1], [10], [11]) -- cgit v1.2.1 From 7f5fe537de3357e36bbb5c385c0aab2fc2bf6a08 Mon Sep 17 00:00:00 2001 From: Jarno Rajahalme Date: Tue, 24 Mar 2015 11:14:43 -0700 Subject: ofproto-dpif-xlate: Restore was_mpls after a patch port. The peer bridge popping MPLS should have no effect on the original bridge. Signed-off-by: Jarno Rajahalme Acked-by: Ben Pfaff --- ofproto/ofproto-dpif-xlate.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index a7cfe06ac..112c7cde2 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -2731,6 +2731,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, if (xport->peer) { const struct xport *peer = xport->peer; struct flow old_flow = ctx->xin->flow; + bool old_was_mpls = ctx->was_mpls; enum slow_path_reason special; uint8_t table_id = rule_dpif_lookup_get_init_table_id(&ctx->xin->flow); struct ofpbuf old_stack = ctx->stack; @@ -2781,6 +2782,10 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, ofpbuf_uninit(&ctx->stack); ctx->stack = old_stack; + /* The peer bridge popping MPLS should have no effect on the original + * bridge. */ + ctx->was_mpls = old_was_mpls; + /* The fact that the peer bridge exits (for any reason) does not mean * that the original bridge should exit. Specifically, if the peer * bridge recirculates (which typically modifies the packet), the -- cgit v1.2.1 From e93ef1c79617c67200835ee05f0605b5c949cc07 Mon Sep 17 00:00:00 2001 From: Jarno Rajahalme Date: Thu, 12 Mar 2015 13:02:07 -0700 Subject: ofproto-dpif-xlate: Remove bond recirculation parameters from context. The bond recirculation parameters in the translation context are short lived and only carry parameters to immediate downstream functions. As such they are better served as normal function parameters. This simplifies the translation context, which needs to be essentially restored after traversing patch ports. Signed-off-by: Jarno Rajahalme Acked-by: Ben Pfaff --- ofproto/ofproto-dpif-xlate.c | 61 ++++++++++++++++++++++++-------------------- ofproto/ofproto-dpif-xlate.h | 6 ----- 2 files changed, 34 insertions(+), 33 deletions(-) diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index 112c7cde2..36c82b031 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -208,14 +208,13 @@ struct xlate_ctx { uint16_t user_cookie_offset;/* Used for user_action_cookie fixup. */ bool exit; /* No further actions should be processed. */ - bool use_recirc; /* Should generate recirc? */ - struct xlate_recirc recirc; /* Information used for generating - * recirculation actions */ - /* True if a packet was but is no longer MPLS (due to an MPLS pop action). * This is a trigger for recirculation in cases where translating an action * or looking up a flow requires access to the fields of the packet after - * the MPLS label stack that was originally present. */ + * the MPLS label stack that was originally present. + * + * XXX: output to a table and patch port do not currently recirculate even + * if this is true. */ bool was_mpls; /* OpenFlow 1.1+ action set. @@ -353,7 +352,16 @@ static bool input_vid_is_valid(uint16_t vid, struct xbundle *, bool warn); static uint16_t input_vid_to_vlan(const struct xbundle *, uint16_t vid); static void output_normal(struct xlate_ctx *, const struct xbundle *, uint16_t vlan); -static void compose_output_action(struct xlate_ctx *, ofp_port_t ofp_port); + +/* Optional bond recirculation parameter to compose_output_action(). */ +struct xlate_bond_recirc { + uint32_t recirc_id; /* !0 Use recirculation instead of output. */ + uint8_t hash_alg; /* !0 Compute hash for recirc before. */ + uint32_t hash_basis; /* Compute hash for recirc before. */ +}; + +static void compose_output_action(struct xlate_ctx *, ofp_port_t ofp_port, + const struct xlate_bond_recirc *xr); static struct xbridge *xbridge_lookup(struct xlate_cfg *, const struct ofproto_dpif *); @@ -1670,28 +1678,28 @@ output_normal(struct xlate_ctx *ctx, const struct xbundle *out_xbundle, uint16_t vid; ovs_be16 tci, old_tci; struct xport *xport; + struct xlate_bond_recirc xr; + bool use_recirc = false; vid = output_vlan_to_vid(out_xbundle, vlan); if (list_is_empty(&out_xbundle->xports)) { /* Partially configured bundle with no slaves. Drop the packet. */ return; } else if (!out_xbundle->bond) { - ctx->use_recirc = false; xport = CONTAINER_OF(list_front(&out_xbundle->xports), struct xport, bundle_node); } else { struct xlate_cfg *xcfg = ovsrcu_get(struct xlate_cfg *, &xcfgp); struct flow_wildcards *wc = &ctx->xout->wc; - struct xlate_recirc *xr = &ctx->recirc; struct ofport_dpif *ofport; if (ctx->xbridge->enable_recirc) { - ctx->use_recirc = bond_may_recirc( - out_xbundle->bond, &xr->recirc_id, &xr->hash_basis); + use_recirc = bond_may_recirc( + out_xbundle->bond, &xr.recirc_id, &xr.hash_basis); - if (ctx->use_recirc) { + if (use_recirc) { /* Only TCP mode uses recirculation. */ - xr->hash_alg = OVS_HASH_ALG_L4; + xr.hash_alg = OVS_HASH_ALG_L4; bond_update_post_recirc_rules(out_xbundle->bond, false); /* Recirculation does not require unmasking hash fields. */ @@ -1708,9 +1716,9 @@ output_normal(struct xlate_ctx *ctx, const struct xbundle *out_xbundle, return; } - /* If ctx->xout->use_recirc is set, the main thread will handle stats + /* If use_recirc is set, the main thread will handle stats * accounting for this bond. */ - if (!ctx->use_recirc) { + if (!use_recirc) { if (ctx->xin->resubmit_stats) { bond_account(out_xbundle->bond, &ctx->xin->flow, vid, ctx->xin->resubmit_stats->n_bytes); @@ -1738,7 +1746,7 @@ output_normal(struct xlate_ctx *ctx, const struct xbundle *out_xbundle, } *flow_tci = tci; - compose_output_action(ctx, xport->ofp_port); + compose_output_action(ctx, xport->ofp_port, use_recirc ? &xr : NULL); *flow_tci = old_tci; } @@ -2673,7 +2681,7 @@ build_tunnel_send(const struct xlate_ctx *ctx, const struct xport *xport, static void compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, - bool check_stp) + const struct xlate_bond_recirc *xr, bool check_stp) { const struct xport *xport = get_ofp_port(ctx->xbridge, ofp_port); struct flow_wildcards *wc = &ctx->xout->wc; @@ -2878,9 +2886,8 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, wc, ctx->xbridge->masked_set_action); - if (ctx->use_recirc) { + if (xr) { struct ovs_action_hash *act_hash; - struct xlate_recirc *xr = &ctx->recirc; /* Hash action. */ act_hash = nl_msg_put_unspec_uninit(ctx->xout->odp_actions, @@ -2936,9 +2943,10 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, } static void -compose_output_action(struct xlate_ctx *ctx, ofp_port_t ofp_port) +compose_output_action(struct xlate_ctx *ctx, ofp_port_t ofp_port, + const struct xlate_bond_recirc *xr) { - compose_output_action__(ctx, ofp_port, true); + compose_output_action__(ctx, ofp_port, xr, true); } static void @@ -3308,9 +3316,9 @@ flood_packets(struct xlate_ctx *ctx, bool all) } if (all) { - compose_output_action__(ctx, xport->ofp_port, false); + compose_output_action__(ctx, xport->ofp_port, NULL, false); } else if (!(xport->config & OFPUTIL_PC_NO_FLOOD)) { - compose_output_action(ctx, xport->ofp_port); + compose_output_action(ctx, xport->ofp_port, NULL); } } @@ -3577,7 +3585,7 @@ xlate_output_action(struct xlate_ctx *ctx, switch (port) { case OFPP_IN_PORT: - compose_output_action(ctx, ctx->xin->flow.in_port.ofp_port); + compose_output_action(ctx, ctx->xin->flow.in_port.ofp_port, NULL); break; case OFPP_TABLE: xlate_table_action(ctx, ctx->xin->flow.in_port.ofp_port, @@ -3604,7 +3612,7 @@ xlate_output_action(struct xlate_ctx *ctx, case OFPP_LOCAL: default: if (port != ctx->xin->flow.in_port.ofp_port) { - compose_output_action(ctx, port); + compose_output_action(ctx, port, NULL); } else { xlate_report(ctx, "skipping output to input port"); } @@ -3663,7 +3671,7 @@ xlate_enqueue_action(struct xlate_ctx *ctx, /* Add datapath actions. */ flow_priority = ctx->xin->flow.skb_priority; ctx->xin->flow.skb_priority = priority; - compose_output_action(ctx, ofp_port); + compose_output_action(ctx, ofp_port, NULL); ctx->xin->flow.skb_priority = flow_priority; /* Update NetFlow output port. */ @@ -4579,7 +4587,6 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) ctx.table_id = 0; ctx.rule_cookie = OVS_BE64_MAX; ctx.exit = false; - ctx.use_recirc = false; ctx.was_mpls = false; if (!xin->ofpacts && !ctx.rule) { @@ -4681,7 +4688,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) if (ctx.xbridge->has_in_band && in_band_must_output_to_local_port(flow) && !actions_output_to_local_port(&ctx)) { - compose_output_action(&ctx, OFPP_LOCAL); + compose_output_action(&ctx, OFPP_LOCAL, NULL); } fix_sflow_action(&ctx); diff --git a/ofproto/ofproto-dpif-xlate.h b/ofproto/ofproto-dpif-xlate.h index a53fa8e4d..3e596fb54 100644 --- a/ofproto/ofproto-dpif-xlate.h +++ b/ofproto/ofproto-dpif-xlate.h @@ -36,12 +36,6 @@ struct mac_learning; struct mcast_snooping; struct xlate_cache; -struct xlate_recirc { - uint32_t recirc_id; /* !0 Use recirculation instead of output. */ - uint8_t hash_alg; /* !0 Compute hash for recirc before. */ - uint32_t hash_basis; /* Compute hash for recirc before. */ -}; - struct xlate_out { /* Wildcards relevant in translation. Any fields that were used to * calculate the action must be set for caching and kernel -- cgit v1.2.1 From 5b09e56908a1b1e79d056e7be8e8a97783b1570d Mon Sep 17 00:00:00 2001 From: Jarno Rajahalme Date: Thu, 19 Mar 2015 15:20:21 -0700 Subject: ofproto-dpif-xlate: Roll back group bucket actions after every bucket. We used to roll back group bucket changes only for 'all' and 'indirect' group types, but the expected semantics of all group types is that any changes by the group bucket are not visible after the group has been executed. Signed-off-by: Jarno Rajahalme Acked-by: Ben Pfaff --- ofproto/ofproto-dpif-xlate.c | 37 +++++++++++++++++++++++++++++-------- tests/ofproto-dpif.at | 12 ++++++++++++ 2 files changed, 41 insertions(+), 8 deletions(-) diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index 36c82b031..391fe3b65 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -3057,6 +3057,8 @@ xlate_group_bucket(struct xlate_ctx *ctx, struct ofputil_bucket *bucket) { uint64_t action_list_stub[1024 / 8]; struct ofpbuf action_list, action_set; + struct flow old_flow = ctx->xin->flow; + bool old_was_mpls = ctx->was_mpls; ofpbuf_use_const(&action_set, bucket->ofpacts, bucket->ofpacts_len); ofpbuf_use_stub(&action_list, action_list_stub, sizeof action_list_stub); @@ -3068,6 +3070,33 @@ xlate_group_bucket(struct xlate_ctx *ctx, struct ofputil_bucket *bucket) ofpbuf_uninit(&action_set); ofpbuf_uninit(&action_list); + + /* Roll back flow to previous state. + * This is equivalent to cloning the packet for each bucket. + * + * As a side effect any subsequently applied actions will + * also effectively be applied to a clone of the packet taken + * just before applying the all or indirect group. + * + * Note that group buckets are action sets, hence they cannot modify the + * main action set. Also any stack actions are ignored when executing an + * action set, so group buckets cannot change the stack either. + * However, we do allow resubmit actions in group buckets, which could + * break the above assumptions. It is up to the controller to not mess up + * with the action_set and stack in the tables resubmitted to from + * group buckets. */ + ctx->xin->flow = old_flow; + + /* The group bucket popping MPLS should have no effect after bucket + * execution. */ + ctx->was_mpls = old_was_mpls; + + /* The fact that the group bucket exits (for any reason) does not mean that + * the translation after the group action should exit. Specifically, if + * the group bucket recirculates (which typically modifies the packet), the + * actions after the group action must continue processing with the + * original, not the recirculated packet! */ + ctx->exit = false; } static void @@ -3075,19 +3104,11 @@ xlate_all_group(struct xlate_ctx *ctx, struct group_dpif *group) { struct ofputil_bucket *bucket; const struct ovs_list *buckets; - struct flow old_flow = ctx->xin->flow; group_dpif_get_buckets(group, &buckets); LIST_FOR_EACH (bucket, list_node, buckets) { xlate_group_bucket(ctx, bucket); - /* Roll back flow to previous state. - * This is equivalent to cloning the packet for each bucket. - * - * As a side effect any subsequently applied actions will - * also effectively be applied to a clone of the packet taken - * just before applying the all or indirect group. */ - ctx->xin->flow = old_flow; } xlate_group_stats(ctx, group, NULL); } diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at index 575217515..b4d7a23da 100644 --- a/tests/ofproto-dpif.at +++ b/tests/ofproto-dpif.at @@ -332,6 +332,18 @@ AT_CHECK([tail -1 stdout], [0], OVS_VSWITCHD_STOP AT_CLEANUP +AT_SETUP([ofproto-dpif - group actions have no effect afterwards]) +OVS_VSWITCHD_START +ADD_OF_PORTS([br0], [1], [10]) +AT_CHECK([ovs-ofctl -O OpenFlow12 add-group br0 'group_id=1234,type=select,bucket=set_field:192.168.3.90->ip_src,output:10']) +AT_CHECK([ovs-ofctl -O OpenFlow12 add-flow br0 'ip actions=group:1234,output:10']) +AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=1,nw_tos=0,nw_ttl=128,icmp_type=8,icmp_code=0'], [0], [stdout]) +AT_CHECK([tail -1 stdout], [0], + [Datapath actions: set(ipv4(src=192.168.3.90,dst=192.168.0.2)),10,set(ipv4(src=192.168.0.1,dst=192.168.0.2)),10 +]) +OVS_VSWITCHD_STOP +AT_CLEANUP + AT_SETUP([ofproto-dpif - all group in action set]) OVS_VSWITCHD_START ADD_OF_PORTS([br0], [1], [10], [11]) -- cgit v1.2.1 From 80e3509d72acecc44d4661f0da5f50a716e23e18 Mon Sep 17 00:00:00 2001 From: Jarno Rajahalme Date: Thu, 19 Mar 2015 15:39:48 -0700 Subject: ofproto-dpif-xlate: More robust wildcarding for select group. The flow key should be the same regardless of whether a live bucket is found or not, as it would be confusing that the flow key would be different (different mask bits) after the last group bucket goes dead. In general, the megaflow algorithm expects the mask bits be set as soon as we read the header bits, regardless of what happens afterwards. Also, use flow_mask_hash_fields() instead of individually setting mask fields. This immediately brings in IPv6 support, and helps keeping masks in sync with potential algorithm changes to flow hashing functions. Found by inspection. Signed-off-by: Jarno Rajahalme Acked-by: Ben Pfaff --- ofproto/ofproto-dpif-xlate.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index 391fe3b65..bdb9d538e 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -3133,18 +3133,9 @@ xlate_default_select_group(struct xlate_ctx *ctx, struct group_dpif *group) uint32_t basis; basis = flow_hash_symmetric_l4(&ctx->xin->flow, 0); + flow_mask_hash_fields(&ctx->xin->flow, wc, NX_HASH_FIELDS_SYMMETRIC_L4); bucket = group_best_live_bucket(ctx, group, basis); if (bucket) { - memset(&wc->masks.dl_dst, 0xff, sizeof wc->masks.dl_dst); - memset(&wc->masks.dl_src, 0xff, sizeof wc->masks.dl_src); - memset(&wc->masks.dl_type, 0xff, sizeof wc->masks.dl_type); - memset(&wc->masks.nw_dst, 0xff, sizeof wc->masks.nw_dst); - memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto); - memset(&wc->masks.nw_src, 0xff, sizeof wc->masks.nw_src); - memset(&wc->masks.tp_dst, 0xff, sizeof wc->masks.tp_dst); - memset(&wc->masks.tp_src, 0xff, sizeof wc->masks.tp_src); - memset(&wc->masks.vlan_tci, 0xff, sizeof wc->masks.vlan_tci); - xlate_group_bucket(ctx, bucket); xlate_group_stats(ctx, group, bucket); } -- cgit v1.2.1 From 4752cc0c26cf6ddfded8f2675b58b6cd3529662a Mon Sep 17 00:00:00 2001 From: Jesse Gross Date: Tue, 24 Mar 2015 07:42:47 -0700 Subject: tunnels: Enable UDP checksum computation for Geneve and VXLAN. The kernel module can already support outer UDP checksums for Geneve and VXLAN using the standard checksum flag in tunnel metadata. This makes userspace aware of the capability so that users can enable it on tunnel ports. There is a complication in that there is no way for userspace to probe or detect if the kernel does not support this capability in order to warn the user. In this case, connectivity will appear to function normally but packets will not be checksum protected. This is mainly an issue for VXLAN which has existed in the kernel for a some time without checksum support - while there are also a few kernel versions that support Geneve only without checksums, they are much less common. There isn't a particularly good solution to the compatibility issue without introducing a larger capabilities structure. However, UDP checksums are likely to be used only rarely at this point in time and the VXLAN spec (where the main problem lies) recommends against them. Therefore, this is considered to be an advanced user feature and we settle for just documenting the issue. Signed-off-by: Jesse Gross Acked-by: Pritesh Kothari --- FAQ.md | 9 +++++++++ NEWS | 1 + lib/netdev-vport.c | 3 ++- vswitchd/vswitch.xml | 26 +++++++++++++++----------- 4 files changed, 27 insertions(+), 12 deletions(-) diff --git a/FAQ.md b/FAQ.md index b112dfb41..21d4e7a67 100644 --- a/FAQ.md +++ b/FAQ.md @@ -207,6 +207,7 @@ A: Support for tunnels was added to the upstream Linux kernel module |:--------:|:-------------: | GRE | 3.11 | VXLAN | 3.12 +| Geneve | 3.18 | LISP | If you are using a version of the kernel that is older than the one @@ -216,6 +217,14 @@ A: Support for tunnels was added to the upstream Linux kernel module persist after doing this, check to make sure that the module that is loaded is the one you expect. +### Q: Why are UDP tunnel checksums not computed for VXLAN or Geneve? + +A: Generating outer UDP checksums requires kernel support that was not + part of the initial implementation of these protocols. If using the + upstream Linux Open vSwitch module, you must use kernel 4.0 or + newer. The out-of-tree modules from Open vSwitch release 2.4 and later + support UDP checksums. + ### Q: What features are not available when using the userspace datapath? A: Tunnel virtual ports are not supported, as described in the diff --git a/NEWS b/NEWS index b8ddc19f3..9f9dc4ce2 100644 --- a/NEWS +++ b/NEWS @@ -76,6 +76,7 @@ Post-v2.3.0 - The default OpenFlow and OVSDB ports are now the IANA-assigned numbers. OpenFlow is 6653 and OVSDB is 6640. - Support for DPDK vHost. + - Support for outer UDP checksums in Geneve and VXLAN. v2.3.0 - 14 Aug 2014 diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c index 8e1b5424a..954ab9bd5 100644 --- a/lib/netdev-vport.c +++ b/lib/netdev-vport.c @@ -426,7 +426,8 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args) struct netdev_tunnel_config tnl_cfg; struct smap_node *node; - has_csum = strstr(type, "gre"); + has_csum = strstr(type, "gre") || strstr(type, "geneve") || + strstr(type, "vxlan"); ipsec_mech_set = false; memset(&tnl_cfg, 0, sizeof tnl_cfg); diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml index e04aefc3e..81e8b3f09 100644 --- a/vswitchd/vswitch.xml +++ b/vswitchd/vswitch.xml @@ -2057,24 +2057,28 @@ - +

- Only gre and ipsec_gre interfaces support - these options. + gre, ipsec_gre, geneve, and + vxlan interfaces support these options.

- Optional. Compute GRE checksums on outgoing packets. Default is - disabled, set to true to enable. Checksums present on - incoming packets will be validated regardless of this setting. + Optional. Compute encapsulation header (either GRE or UDP) + checksums on outgoing packets. Default is disabled, set to + true to enable. Checksums present on incoming + packets will be validated regardless of this setting.

-

- GRE checksums impose a significant performance penalty because they - cover the entire packet. The encapsulated L3, L4, and L7 packet - contents typically have their own checksums, so this additional - checksum only adds value for the GRE and encapsulated L2 headers. +

+ When using the upstream Linux kernel module, computation of + checksums for geneve and vxlan requires + Linux kernel version 4.0 or higher. gre supports + checksums for all versions of Open vSwitch that support GRE. + The out of tree kernel module distributed as part of OVS + can compute all tunnel checksums on any kernel version that it + is compatible with.

-- cgit v1.2.1 From 2f4298ce26b1130c63d2e8b21da13c22986bdeef Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Tue, 24 Mar 2015 10:51:56 -0700 Subject: netdev-linux: Fix build with old kernel headers. Commit 677d9158fc0a (netdev-linux: Support for SFQ, FQ_CoDel and CoDel qdiscs.) added support for new qdiscs. The commit uses TCA_CODEL_* and TCA_FQ_CODEL_* not in old kernel headers, causing a build failure against such headers. This commit should fix the problem by defining these values ourselves. (I haven't tested it against old headers, so I might have missed something, but it's a straightforward change and at worst won't do harm.) It appears that sfq (also added by the same commit) was in Linux before 2.6.32, so it seems unlikely that we need any compatibility code there. CC: Jonathan Vestin Signed-off-by: Ben Pfaff --- lib/netdev-linux.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index 8253dfb4b..5e6f01ef6 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -2841,6 +2841,14 @@ const struct netdev_class netdev_internal_class = #define CODEL_N_QUEUES 0x0000 +/* In sufficiently new kernel headers these are defined as enums in + * . Define them here as macros to help out with older + * kernels. (This overrides any enum definition in the header file but that's + * harmless.) */ +#define TCA_CODEL_TARGET 1 +#define TCA_CODEL_LIMIT 2 +#define TCA_CODEL_INTERVAL 3 + struct codel { struct tc tc; uint32_t target; @@ -3052,6 +3060,17 @@ static const struct tc_ops tc_ops_codel = { #define FQCODEL_N_QUEUES 0x0000 +/* In sufficiently new kernel headers these are defined as enums in + * . Define them here as macros to help out with older + * kernels. (This overrides any enum definition in the header file but that's + * harmless.) */ +#define TCA_FQ_CODEL_TARGET 1 +#define TCA_FQ_CODEL_LIMIT 2 +#define TCA_FQ_CODEL_INTERVAL 3 +#define TCA_FQ_CODEL_ECN 4 +#define TCA_FQ_CODEL_FLOWS 5 +#define TCA_FQ_CODEL_QUANTUM 6 + struct fqcodel { struct tc tc; uint32_t target; -- cgit v1.2.1 From da79ce2b71dd879e7f20fdddc715568f6a74185a Mon Sep 17 00:00:00 2001 From: Daniele Di Proietto Date: Thu, 12 Mar 2015 18:04:32 +0000 Subject: netdev-dpdk: create smaller mempools in case of failure If rte_mempool_create() fails with ENOMEM, try asking for a smaller mempools. This patch enables OVS DPDK to run on systems without 1GB hugepages Signed-off-by: Daniele Di Proietto Acked-by: Ethan Jackson --- lib/netdev-dpdk.c | 46 +++++++++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c index a4775fda0..4e16f3916 100644 --- a/lib/netdev-dpdk.c +++ b/lib/netdev-dpdk.c @@ -68,9 +68,23 @@ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20); #define MBUF_SIZE(mtu) (MTU_TO_MAX_LEN(mtu) + (512) + \ sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM) -/* XXX: mempool size should be based on system resources. */ -#define NB_MBUF (4096 * 64) -#define MP_CACHE_SZ (256 * 2) +/* Max and min number of packets in the mempool. OVS tries to allocate a + * mempool with MAX_NB_MBUF: if this fails (because the system doesn't have + * enough hugepages) we keep halving the number until the allocation succeeds + * or we reach MIN_NB_MBUF */ + +#define MAX_NB_MBUF (4096 * 64) +#define MIN_NB_MBUF (4096 * 4) +#define MP_CACHE_SZ RTE_MEMPOOL_CACHE_MAX_SIZE + +/* MAX_NB_MBUF can be divided by 2 many times, until MIN_NB_MBUF */ +BUILD_ASSERT_DECL(MAX_NB_MBUF % ROUND_DOWN_POW2(MAX_NB_MBUF/MIN_NB_MBUF) == 0); + +/* The smallest possible NB_MBUF that we're going to try should be a multiple + * of MP_CACHE_SZ. This is advised by DPDK documentation. */ +BUILD_ASSERT_DECL((MAX_NB_MBUF / ROUND_DOWN_POW2(MAX_NB_MBUF/MIN_NB_MBUF)) + % MP_CACHE_SZ == 0); + #define SOCKET0 0 #define NIC_PORT_RX_Q_SIZE 2048 /* Size of Physical NIC RX Queue, Max (n+32<=4096)*/ @@ -310,6 +324,7 @@ dpdk_mp_get(int socket_id, int mtu) OVS_REQUIRES(dpdk_mutex) { struct dpdk_mp *dmp = NULL; char mp_name[RTE_MEMPOOL_NAMESIZE]; + unsigned mp_size; LIST_FOR_EACH (dmp, list_node, &dpdk_mp_list) { if (dmp->socket_id == socket_id && dmp->mtu == mtu) { @@ -323,20 +338,25 @@ dpdk_mp_get(int socket_id, int mtu) OVS_REQUIRES(dpdk_mutex) dmp->mtu = mtu; dmp->refcount = 1; - if (snprintf(mp_name, RTE_MEMPOOL_NAMESIZE, "ovs_mp_%d_%d", dmp->mtu, - dmp->socket_id) < 0) { - return NULL; - } + mp_size = MAX_NB_MBUF; + do { + if (snprintf(mp_name, RTE_MEMPOOL_NAMESIZE, "ovs_mp_%d_%d_%u", + dmp->mtu, dmp->socket_id, mp_size) < 0) { + return NULL; + } - dmp->mp = rte_mempool_create(mp_name, NB_MBUF, MBUF_SIZE(mtu), - MP_CACHE_SZ, - sizeof(struct rte_pktmbuf_pool_private), - rte_pktmbuf_pool_init, NULL, - ovs_rte_pktmbuf_init, NULL, - socket_id, 0); + dmp->mp = rte_mempool_create(mp_name, mp_size, MBUF_SIZE(mtu), + MP_CACHE_SZ, + sizeof(struct rte_pktmbuf_pool_private), + rte_pktmbuf_pool_init, NULL, + ovs_rte_pktmbuf_init, NULL, + socket_id, 0); + } while (!dmp->mp && rte_errno == ENOMEM && (mp_size /= 2) >= MIN_NB_MBUF); if (dmp->mp == NULL) { return NULL; + } else { + VLOG_DBG("Allocated \"%s\" mempool with %u mbufs", mp_name, mp_size ); } list_push_back(&dpdk_mp_list, &dmp->list_node); -- cgit v1.2.1 From 13dd4a9738e99684a56b10ce2f1a5ee2d2ec2f9f Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Tue, 24 Mar 2015 16:16:18 -0700 Subject: compat: Fix RHEL7 build. Tested against 3.10.0-229.el7.x86_64. Signed-off-by: Joe Stringer Acked-by: Pravin B Shelar --- acinclude.m4 | 48 ++++++++++++++++++++++++++- datapath/compat.h | 6 ++-- datapath/linux/compat/genetlink-openvswitch.c | 2 +- datapath/linux/compat/include/linux/skbuff.h | 5 ++- datapath/linux/compat/include/net/genetlink.h | 6 +++- datapath/linux/compat/include/net/ip.h | 2 +- datapath/linux/compat/include/net/udp.h | 19 +++++++++-- datapath/linux/compat/udp.c | 2 +- 8 files changed, 78 insertions(+), 12 deletions(-) diff --git a/acinclude.m4 b/acinclude.m4 index 5ed70c172..479da2e2e 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -254,6 +254,37 @@ AC_DEFUN([OVS_GREP_IFELSE], [ fi ]) +dnl OVS_FIND_FIELD_IFELSE(FILE, STRUCTURE, REGEX, [IF-MATCH], [IF-NO-MATCH]) +dnl +dnl Looks for STRUCTURE in FILE. If it is found, greps for REGEX within the +dnl structure definition. If this is successful, runs IF-MATCH, otherwise +dnl IF_NO_MATCH. If IF-MATCH is empty then it defines to +dnl OVS_DEFINE(HAVE__WITH_), with and +dnl translated to uppercase. +AC_DEFUN([OVS_FIND_FIELD_IFELSE], [ + AC_MSG_CHECKING([whether $2 has member $3 in $1]) + if test -f $1; then + awk '/$2.{/,/^}/' $1 2>/dev/null | grep '$3' + status=$? + case $status in + 0) + AC_MSG_RESULT([yes]) + m4_if([$4], [], [OVS_DEFINE([HAVE_]m4_toupper([$2])[_WITH_]m4_toupper([$3]))], [$4]) + ;; + 1) + AC_MSG_RESULT([no]) + $5 + ;; + *) + AC_MSG_ERROR([grep exited with status $status]) + ;; + esac + else + AC_MSG_RESULT([file not found]) + $5 + fi +]) + dnl OVS_DEFINE(NAME) dnl dnl Defines NAME to 1 in kcompat.h. @@ -294,6 +325,8 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [ OVS_GREP_IFELSE([$KSRC/include/linux/in.h], [ipv4_is_multicast]) OVS_GREP_IFELSE([$KSRC/include/net/ip.h], [__ip_select_ident.*dst_entry], [OVS_DEFINE([HAVE_IP_SELECT_IDENT_USING_DST_ENTRY])]) + OVS_GREP_IFELSE([$KSRC/include/net/ip.h], [inet_get_local_port_range.*net], + [OVS_DEFINE([HAVE_INET_GET_LOCAL_PORT_RANGE_USING_NET])]) OVS_GREP_IFELSE([$KSRC/include/linux/netdevice.h], [dev_disable_lro]) OVS_GREP_IFELSE([$KSRC/include/linux/netdevice.h], [dev_get_stats]) @@ -366,6 +399,12 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [ OVS_GREP_IFELSE([$KSRC/include/net/genetlink.h], [netlink_has_listeners(net->genl_sock], [OVS_DEFINE([HAVE_GENL_HAS_LISTENERS_TAKES_NET])]) OVS_GREP_IFELSE([$KSRC/include/net/genetlink.h], [genlmsg_parse]) + OVS_GREP_IFELSE([$KSRC/include/net/genetlink.h], [genl_notify.*family], + [OVS_DEFINE([HAVE_GENL_NOTIFY_TAKES_FAMILY])]) + + OVS_FIND_FIELD_IFELSE([$KSRC/include/net/genetlink.h], + [genl_multicast_group], [id]) + OVS_GREP_IFELSE([$KSRC/include/net/gre.h], [gre_cisco_register]) OVS_GREP_IFELSE([$KSRC/include/net/ipv6.h], [IP6_FH_F_SKIP_RH]) OVS_GREP_IFELSE([$KSRC/include/net/netlink.h], [nla_get_be16]) @@ -390,9 +429,16 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [ OVS_GREP_IFELSE([$KSRC/include/net/vxlan.h], [struct vxlan_metadata], [OVS_DEFINE([HAVE_VXLAN_METADATA])]) OVS_GREP_IFELSE([$KSRC/include/net/udp.h], [udp_flow_src_port], - [OVS_DEFINE([HAVE_UDP_FLOW_SRC_PORT])]) + [OVS_GREP_IFELSE([$KSRC/include/net/udp.h], [inet_get_local_port_range(net], + [OVS_DEFINE([HAVE_UDP_FLOW_SRC_PORT])])]) + OVS_GREP_IFELSE([$KSRC/include/net/udp.h], [udp_v4_check]) + OVS_GREP_IFELSE([$KSRC/include/net/udp.h], [udp_set_csum]) OVS_GREP_IFELSE([$KSRC/include/linux/skbuff.h], [ignore_df:1], [OVS_DEFINE([HAVE_IGNORE_DF_RENAME])]) + OVS_GREP_IFELSE([$KSRC/include/linux/skbuff.h], [SKB_GSO_GRE_CSUM], + [OVS_DEFINE([HAVE_SKB_GSO_GRE_CSUM])]) + OVS_GREP_IFELSE([$KSRC/include/linux/skbuff.h], [SKB_GSO_UDP_TUNNEL_CSUM], + [OVS_DEFINE([HAVE_SKB_GSO_UDP_TUNNEL_CSUM])]) OVS_GREP_IFELSE([$KSRC/include/uapi/linux/netdevice.h], [NET_NAME_UNKNOWN], [OVS_DEFINE([HAVE_NET_NAME_UNKNOWN])]) diff --git a/datapath/compat.h b/datapath/compat.h index 5ef626fdb..c827b11aa 100644 --- a/datapath/compat.h +++ b/datapath/compat.h @@ -25,10 +25,10 @@ #include #include -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,13,0) -#define GROUP_ID(grp) 0 -#else +#ifdef HAVE_GENL_MULTICAST_GROUP_WITH_ID #define GROUP_ID(grp) ((grp)->id) +#else +#define GROUP_ID(grp) 0 #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36) diff --git a/datapath/linux/compat/genetlink-openvswitch.c b/datapath/linux/compat/genetlink-openvswitch.c index 08f0fab8b..ab149c35d 100644 --- a/datapath/linux/compat/genetlink-openvswitch.c +++ b/datapath/linux/compat/genetlink-openvswitch.c @@ -1,7 +1,7 @@ #include #include -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0) +#ifndef HAVE_GENL_NOTIFY_TAKES_FAMILY #undef genl_notify diff --git a/datapath/linux/compat/include/linux/skbuff.h b/datapath/linux/compat/include/linux/skbuff.h index 78d84cc2b..d14719232 100644 --- a/datapath/linux/compat/include/linux/skbuff.h +++ b/datapath/linux/compat/include/linux/skbuff.h @@ -14,8 +14,11 @@ #define SKB_GSO_UDP_TUNNEL 0 #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,16,0) +#ifndef HAVE_SKB_GSO_GRE_CSUM #define SKB_GSO_GRE_CSUM 0 +#endif + +#ifndef HAVE_SKB_GSO_UDP_TUNNEL_CSUM #define SKB_GSO_UDP_TUNNEL_CSUM 0 #endif diff --git a/datapath/linux/compat/include/net/genetlink.h b/datapath/linux/compat/include/net/genetlink.h index 9edfd3142..edf681562 100644 --- a/datapath/linux/compat/include/net/genetlink.h +++ b/datapath/linux/compat/include/net/genetlink.h @@ -17,7 +17,7 @@ #define portid pid #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0) +#ifndef HAVE_GENL_NOTIFY_TAKES_FAMILY struct rpl_genl_family { struct genl_family compat_family; unsigned int id; @@ -122,7 +122,11 @@ static inline int genl_has_listeners(struct genl_family *family, static inline int rpl_genl_has_listeners(struct genl_family *family, struct net *net, unsigned int group) { +#ifdef HAVE_GENL_NOTIFY_TAKES_FAMILY return genl_has_listeners(family, net->genl_sock, group); +#else + return genl_has_listeners(&family->compat_family, net->genl_sock, group); +#endif } #define genl_has_listeners rpl_genl_has_listeners diff --git a/datapath/linux/compat/include/net/ip.h b/datapath/linux/compat/include/net/ip.h index c819e4d99..b60617750 100644 --- a/datapath/linux/compat/include/net/ip.h +++ b/datapath/linux/compat/include/net/ip.h @@ -12,7 +12,7 @@ static inline bool ip_is_fragment(const struct iphdr *iph) } #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0) +#ifndef HAVE_INET_GET_LOCAL_PORT_RANGE_USING_NET static inline void rpl_inet_get_local_port_range(struct net *net, int *low, int *high) { diff --git a/datapath/linux/compat/include/net/udp.h b/datapath/linux/compat/include/net/udp.h index f1841d4a2..02eb68878 100644 --- a/datapath/linux/compat/include/net/udp.h +++ b/datapath/linux/compat/include/net/udp.h @@ -2,11 +2,20 @@ #define __NET_UDP_WRAPPER_H 1 #include + +#ifdef inet_get_local_port_range +/* RHEL7 backports udp_flow_src_port() using an older version of + * inet_get_local_port_range(). */ +#undef inet_get_local_port_range +#include_next +#define inet_get_local_port_range rpl_inet_get_local_port_range +#else #include_next +#endif #ifndef HAVE_UDP_FLOW_SRC_PORT -static inline __be16 udp_flow_src_port(struct net *net, struct sk_buff *skb, - int min, int max, bool use_eth) +static inline __be16 rpl_udp_flow_src_port(struct net *net, struct sk_buff *skb, + int min, int max, bool use_eth) { u32 hash; @@ -33,15 +42,19 @@ static inline __be16 udp_flow_src_port(struct net *net, struct sk_buff *skb, return htons((((u64) hash * (max - min)) >> 32) + min); } + +#define udp_flow_src_port rpl_udp_flow_src_port #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,16,0) +#ifndef HAVE_UDP_V4_CHECK static inline __sum16 udp_v4_check(int len, __be32 saddr, __be32 daddr, __wsum base) { return csum_tcpudp_magic(saddr, daddr, len, IPPROTO_UDP, base); } +#endif +#ifndef HAVE_UDP_SET_CSUM void udp_set_csum(bool nocheck, struct sk_buff *skb, __be32 saddr, __be32 daddr, int len); #endif diff --git a/datapath/linux/compat/udp.c b/datapath/linux/compat/udp.c index a27928f2c..834a86b71 100644 --- a/datapath/linux/compat/udp.c +++ b/datapath/linux/compat/udp.c @@ -1,6 +1,6 @@ #include -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,16,0) +#ifndef HAVE_UDP_SET_CSUM #include -- cgit v1.2.1 From e672ff9b4d224f4d7ef12b289811b0759a333e48 Mon Sep 17 00:00:00 2001 From: Jarno Rajahalme Date: Thu, 26 Mar 2015 11:18:16 -0700 Subject: ofproto-dpif: Restore metadata and registers on recirculation. xlate_actions() now considers an optional recirculation context (via 'xin') and restores OpenFlow pipeline metadata (registers, 'metadata', etc.) based on it. The recirculation context may contain an action set and stack to be restored and further actions to be executed upon recirculation. It also contains a table_id number to be used for rule lookup in cases where no post-recirculation actions are used. The translation context internal metadata is restored using a new internal action: UNROLL_XLATE action stores the translation context data visible to OpenFlow controllers via PACKET_IN messages. This includes the current table number and the current rule cookie. UNROLL_XLATE actions are inserted only when the remaining actions may generate PACKET_IN messages. These changes allow the post-MPLS recirculation to properly continue with the pipeline metadata that existed at the time of recirculation. The internal table is still consulted for bonds. Signed-off-by: Jarno Rajahalme Acked-by: Ethan Jackson Acked-by: Ben Pfaff --- lib/ofp-actions.c | 36 ++- lib/ofp-actions.h | 12 + ofproto/bond.c | 7 +- ofproto/ofproto-dpif-rid.c | 358 ++++++++++++++++++++++--- ofproto/ofproto-dpif-rid.h | 167 ++++++++++-- ofproto/ofproto-dpif-upcall.c | 103 ++++++-- ofproto/ofproto-dpif-xlate.c | 596 +++++++++++++++++++++++++++++++----------- ofproto/ofproto-dpif-xlate.h | 66 +++++ ofproto/ofproto-dpif.c | 177 ++----------- ofproto/ofproto-dpif.h | 92 +------ tests/mpls-xlate.at | 22 +- tests/ofproto-dpif.at | 205 ++++++++------- 12 files changed, 1261 insertions(+), 580 deletions(-) diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c index 260d85474..65fa64d08 100644 --- a/lib/ofp-actions.c +++ b/lib/ofp-actions.c @@ -4237,6 +4237,31 @@ format_EXIT(const struct ofpact_null *a OVS_UNUSED, struct ds *s) ds_put_cstr(s, "exit"); } +/* Unroll xlate action. */ + +static void +encode_UNROLL_XLATE(const struct ofpact_unroll_xlate *unroll OVS_UNUSED, + enum ofp_version ofp_version OVS_UNUSED, + struct ofpbuf *out OVS_UNUSED) +{ + OVS_NOT_REACHED(); +} + +static char * OVS_WARN_UNUSED_RESULT +parse_UNROLL_XLATE(char *arg OVS_UNUSED, struct ofpbuf *ofpacts OVS_UNUSED, + enum ofputil_protocol *usable_protocols OVS_UNUSED) +{ + OVS_NOT_REACHED(); + return NULL; +} + +static void +format_UNROLL_XLATE(const struct ofpact_unroll_xlate *a OVS_UNUSED, + struct ds *s) +{ + ds_put_cstr(s, "unroll_xlate"); +} + /* Action structure for NXAST_SAMPLE. * * Samples matching packets with the given probability and sends them @@ -4726,6 +4751,7 @@ ofpact_is_set_or_move_action(const struct ofpact *a) case OFPACT_DEC_TTL: case OFPACT_ENQUEUE: case OFPACT_EXIT: + case OFPACT_UNROLL_XLATE: case OFPACT_FIN_TIMEOUT: case OFPACT_GOTO_TABLE: case OFPACT_GROUP: @@ -4795,6 +4821,7 @@ ofpact_is_allowed_in_actions_set(const struct ofpact *a) case OFPACT_CONTROLLER: case OFPACT_ENQUEUE: case OFPACT_EXIT: + case OFPACT_UNROLL_XLATE: case OFPACT_FIN_TIMEOUT: case OFPACT_LEARN: case OFPACT_CONJUNCTION: @@ -4868,7 +4895,7 @@ ofpacts_copy_all(struct ofpbuf *out, const struct ofpbuf *in, * "Action Set" and "Action List" terms used in OpenFlow 1.1+.) * * In general this involves appending the last instance of each action that is - * adimissible in the action set in the order described in the OpenFlow + * admissible in the action set in the order described in the OpenFlow * specification. * * Exceptions: @@ -5017,6 +5044,7 @@ ovs_instruction_type_from_ofpact_type(enum ofpact_type type) case OFPACT_MULTIPATH: case OFPACT_NOTE: case OFPACT_EXIT: + case OFPACT_UNROLL_XLATE: case OFPACT_SAMPLE: default: return OVSINST_OFPIT11_APPLY_ACTIONS; @@ -5607,6 +5635,11 @@ ofpact_check__(enum ofputil_protocol *usable_protocols, struct ofpact *a, case OFPACT_GROUP: return 0; + case OFPACT_UNROLL_XLATE: + /* UNROLL is an internal action that should never be seen via + * OpenFlow. */ + return OFPERR_OFPBAC_BAD_TYPE; + default: OVS_NOT_REACHED(); } @@ -5998,6 +6031,7 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, ofp_port_t port) case OFPACT_MULTIPATH: case OFPACT_NOTE: case OFPACT_EXIT: + case OFPACT_UNROLL_XLATE: case OFPACT_PUSH_MPLS: case OFPACT_POP_MPLS: case OFPACT_SAMPLE: diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h index a1a5bb122..785c8140c 100644 --- a/lib/ofp-actions.h +++ b/lib/ofp-actions.h @@ -105,6 +105,7 @@ OFPACT(NOTE, ofpact_note, data, "note") \ OFPACT(EXIT, ofpact_null, ofpact, "exit") \ OFPACT(SAMPLE, ofpact_sample, ofpact, "sample") \ + OFPACT(UNROLL_XLATE, ofpact_unroll_xlate, ofpact, "unroll_xlate") \ \ /* Instructions. */ \ OFPACT(METER, ofpact_meter, ofpact, "meter") \ @@ -715,6 +716,17 @@ struct ofpact_group { uint32_t group_id; }; +/* OFPACT_UNROLL_XLATE. + * + * Used only internally. */ +struct ofpact_unroll_xlate { + struct ofpact ofpact; + + /* Metadata in xlate context, visible to controller via PACKET_INs. */ + uint8_t rule_table_id; /* 0xFF if none. */ + ovs_be64 rule_cookie; /* OVS_BE64_MAX if none. */ +}; + /* Converting OpenFlow to ofpacts. */ enum ofperr ofpacts_pull_openflow_actions(struct ofpbuf *openflow, unsigned int actions_len, diff --git a/ofproto/bond.c b/ofproto/bond.c index 7831fa41e..2e3ad2957 100644 --- a/ofproto/bond.c +++ b/ofproto/bond.c @@ -28,6 +28,7 @@ #include "ofpbuf.h" #include "ofproto/ofproto-provider.h" #include "ofproto/ofproto-dpif.h" +#include "ofproto/ofproto-dpif-rid.h" #include "connectivity.h" #include "coverage.h" #include "dynamic-string.h" @@ -289,7 +290,7 @@ bond_unref(struct bond *bond) hmap_destroy(&bond->pr_rule_ops); if (bond->recirc_id) { - ofproto_dpif_free_recirc_id(bond->ofproto, bond->recirc_id); + recirc_free_id(bond->recirc_id); } free(bond); @@ -446,10 +447,10 @@ bond_reconfigure(struct bond *bond, const struct bond_settings *s) if (bond->balance != BM_AB) { if (!bond->recirc_id) { - bond->recirc_id = ofproto_dpif_alloc_recirc_id(bond->ofproto); + bond->recirc_id = recirc_alloc_id(bond->ofproto); } } else if (bond->recirc_id) { - ofproto_dpif_free_recirc_id(bond->ofproto, bond->recirc_id); + recirc_free_id(bond->recirc_id); bond->recirc_id = 0; } diff --git a/ofproto/ofproto-dpif-rid.c b/ofproto/ofproto-dpif-rid.c index afad3ce34..17bcede62 100644 --- a/ofproto/ofproto-dpif-rid.c +++ b/ofproto/ofproto-dpif-rid.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Nicira, Inc. + * Copyright (c) 2014, 2015 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,59 +16,351 @@ #include -#include "id-pool.h" -#include "ovs-thread.h" +#include "ofpbuf.h" +#include "ofproto-dpif.h" #include "ofproto-dpif-rid.h" +#include "ofproto-provider.h" +#include "openvswitch/vlog.h" -struct recirc_id_pool { - struct ovs_mutex lock; - struct id_pool *rids; -}; +VLOG_DEFINE_THIS_MODULE(ofproto_dpif_rid); -#define RECIRC_ID_BASE 300 -#define RECIRC_ID_N_IDS 1024 +static struct ovs_mutex mutex; -struct recirc_id_pool * -recirc_id_pool_create(void) +static struct cmap id_map; +static struct cmap metadata_map; + +static struct ovs_list expiring OVS_GUARDED_BY(mutex); +static struct ovs_list expired OVS_GUARDED_BY(mutex); + +static uint32_t next_id OVS_GUARDED_BY(mutex); /* Possible next free id. */ + +#define RECIRC_POOL_STATIC_IDS 1024 + +void +recirc_init(void) { - struct recirc_id_pool *pool; + static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER; - pool = xmalloc(sizeof *pool); - pool->rids = id_pool_create(RECIRC_ID_BASE, RECIRC_ID_N_IDS); - ovs_mutex_init(&pool->lock); + if (ovsthread_once_start(&once)) { + ovs_mutex_init(&mutex); + ovs_mutex_lock(&mutex); + next_id = 1; /* 0 is not a valid ID. */ + cmap_init(&id_map); + cmap_init(&metadata_map); + list_init(&expiring); + list_init(&expired); + ovs_mutex_unlock(&mutex); + + ovsthread_once_done(&once); + } - return pool; } +/* This should be called by the revalidator once at each round (every 500ms or + * more). */ void -recirc_id_pool_destroy(struct recirc_id_pool *pool) +recirc_run(void) +{ + static long long int last = 0; + long long int now = time_msec(); + + /* Do maintenance at most 4 times / sec. */ + ovs_mutex_lock(&mutex); + if (now - last > 250) { + struct recirc_id_node *node, *next; + + last = now; + + /* Nodes in 'expiring' and 'expired' lists have the refcount of zero, + * which means that while they can still be found (by id), no new + * references can be taken on them. We have removed the entry from the + * 'metadata_map', at the time when refcount reached zero, causing any + * new translations to allocate a new ID. This allows the expiring + * entry to be safely deleted while any sudden new use of the similar + * recirculation will safely start using a new recirculation ID. When + * the refcount gets to zero, the node is also added to the 'expiring' + * list. At any time after that the nodes in the 'expiring' list can + * be moved to the 'expired' list, from which they are deleted at least + * 250ms afterwards. */ + + /* Delete the expired. These have been lingering for at least 250 ms, + * which should be enough for any ongoing recirculations to be + * finished. */ + LIST_FOR_EACH_SAFE (node, next, exp_node, &expired) { + list_remove(&node->exp_node); + cmap_remove(&id_map, &node->id_node, node->id); + ovsrcu_postpone(free, node); + } + + if (!list_is_empty(&expiring)) { + /* 'expired' is now empty, move nodes in 'expiring' to it. */ + list_splice(&expired, list_front(&expiring), &expiring); + } + } + ovs_mutex_unlock(&mutex); +} + +/* We use the id as the hash value, which works due to cmap internal rehashing. + * We also only insert nodes with unique IDs, so all possible hash collisions + * remain internal to the cmap. */ +static struct recirc_id_node * +recirc_find__(uint32_t id) + OVS_REQUIRES(mutex) +{ + struct cmap_node *node = cmap_find_protected(&id_map, id); + + return node ? CONTAINER_OF(node, struct recirc_id_node, id_node) : NULL; +} + +/* Lockless RCU protected lookup. If node is needed accross RCU quiescent + * state, caller should copy the contents. */ +const struct recirc_id_node * +recirc_id_node_find(uint32_t id) +{ + const struct cmap_node *node = cmap_find(&id_map, id); + + return node + ? CONTAINER_OF(node, const struct recirc_id_node, id_node) + : NULL; +} + +static uint32_t +recirc_metadata_hash(struct ofproto_dpif *ofproto, uint8_t table_id, + struct recirc_metadata *md, struct ofpbuf *stack, + uint32_t action_set_len, uint32_t ofpacts_len, + const struct ofpact *ofpacts) +{ + uint32_t hash; + + BUILD_ASSERT(OFPACT_ALIGNTO == sizeof(uint64_t)); + + hash = hash_pointer(ofproto, 0); + hash = hash_int(table_id, hash); + hash = hash_words64((const uint64_t *)md, sizeof *md / sizeof(uint64_t), + hash); + if (stack && stack->size != 0) { + hash = hash_words64((const uint64_t *)stack->data, + stack->size / sizeof(uint64_t), hash); + } + hash = hash_int(action_set_len, hash); + if (ofpacts_len) { + hash = hash_words64(ALIGNED_CAST(const uint64_t *, ofpacts), + OFPACT_ALIGN(ofpacts_len) / sizeof(uint64_t), + hash); + } + return hash; +} + +static bool +recirc_metadata_equal(const struct recirc_id_node *node, + struct ofproto_dpif *ofproto, uint8_t table_id, + struct recirc_metadata *md, struct ofpbuf *stack, + uint32_t action_set_len, uint32_t ofpacts_len, + const struct ofpact *ofpacts) +{ + return node->ofproto == ofproto + && node->table_id == table_id + && !memcmp(&node->metadata, md, sizeof *md) + && ((!node->stack && (!stack || stack->size == 0)) + || (node->stack && stack && ofpbuf_equal(node->stack, stack))) + && node->action_set_len == action_set_len + && node->ofpacts_len == ofpacts_len + && (ofpacts_len == 0 || !memcmp(node->ofpacts, ofpacts, ofpacts_len)); +} + +/* Lockless RCU protected lookup. If node is needed accross RCU quiescent + * state, caller should take a reference. */ +static struct recirc_id_node * +recirc_find_equal(struct ofproto_dpif *ofproto, uint8_t table_id, + struct recirc_metadata *md, struct ofpbuf *stack, + uint32_t action_set_len, uint32_t ofpacts_len, + const struct ofpact *ofpacts, uint32_t hash) +{ + struct recirc_id_node *node; + + CMAP_FOR_EACH_WITH_HASH(node, metadata_node, hash, &metadata_map) { + if (recirc_metadata_equal(node, ofproto, table_id, md, stack, + action_set_len, ofpacts_len, ofpacts)) { + return node; + } + } + return NULL; +} + +static struct recirc_id_node * +recirc_ref_equal(struct ofproto_dpif *ofproto, uint8_t table_id, + struct recirc_metadata *md, struct ofpbuf *stack, + uint32_t action_set_len, uint32_t ofpacts_len, + const struct ofpact *ofpacts, uint32_t hash) +{ + struct recirc_id_node *node; + + do { + node = recirc_find_equal(ofproto, table_id, md, stack, action_set_len, + ofpacts_len, ofpacts, hash); + + /* Try again if the node was released before we get the reference. */ + } while (node && !ovs_refcount_try_ref_rcu(&node->refcount)); + + return node; +} + +/* Allocate a unique recirculation id for the given set of flow metadata. + * The ID space is 2^^32, so there should never be a situation in which all + * the IDs are used up. We loop until we find a free one. + * hash is recomputed if it is passed in as 0. */ +static struct recirc_id_node * +recirc_alloc_id__(struct ofproto_dpif *ofproto, uint8_t table_id, + struct recirc_metadata *md, struct ofpbuf *stack, + uint32_t action_set_len, uint32_t ofpacts_len, + const struct ofpact *ofpacts, uint32_t hash) +{ + struct recirc_id_node *node = xzalloc(sizeof *node + + OFPACT_ALIGN(ofpacts_len)); + node->hash = hash; + ovs_refcount_init(&node->refcount); + + node->ofproto = ofproto; + node->table_id = table_id; + memcpy(&node->metadata, md, sizeof node->metadata); + node->stack = (stack && stack->size) ? ofpbuf_clone(stack) : NULL; + node->action_set_len = action_set_len; + node->ofpacts_len = ofpacts_len; + if (ofpacts_len) { + memcpy(node->ofpacts, ofpacts, ofpacts_len); + } + + ovs_mutex_lock(&mutex); + for (;;) { + /* Claim the next ID. The ID space should be sparse enough for the + allocation to succeed at the first try. We do skip the first + RECIRC_POOL_STATIC_IDS IDs on the later rounds, though, as some of + the initial allocations may be for long term uses (like bonds). */ + node->id = next_id++; + if (OVS_UNLIKELY(!node->id)) { + next_id = RECIRC_POOL_STATIC_IDS + 1; + node->id = next_id++; + } + /* Find if the id is free. */ + if (OVS_LIKELY(!recirc_find__(node->id))) { + break; + } + } + cmap_insert(&id_map, &node->id_node, node->id); + cmap_insert(&metadata_map, &node->metadata_node, node->hash); + ovs_mutex_unlock(&mutex); + return node; +} + +/* Look up an existing ID for the given flow's metadata and optional actions. + */ +uint32_t +recirc_find_id(struct ofproto_dpif *ofproto, uint8_t table_id, + struct recirc_metadata *md, struct ofpbuf *stack, + uint32_t action_set_len, uint32_t ofpacts_len, + const struct ofpact *ofpacts) +{ + /* Check if an ID with the given metadata already exists. */ + struct recirc_id_node *node; + uint32_t hash; + + hash = recirc_metadata_hash(ofproto, table_id, md, stack, action_set_len, + ofpacts_len, ofpacts); + node = recirc_find_equal(ofproto, table_id, md, stack, action_set_len, + ofpacts_len, ofpacts, hash); + + return node ? node->id : 0; +} + +/* Allocate a unique recirculation id for the given set of flow metadata and + optional actions. */ +uint32_t +recirc_alloc_id_ctx(struct ofproto_dpif *ofproto, uint8_t table_id, + struct recirc_metadata *md, struct ofpbuf *stack, + uint32_t action_set_len, uint32_t ofpacts_len, + const struct ofpact *ofpacts) { - id_pool_destroy(pool->rids); - ovs_mutex_destroy(&pool->lock); - free(pool); + struct recirc_id_node *node; + uint32_t hash; + + /* Look up an existing ID. */ + hash = recirc_metadata_hash(ofproto, table_id, md, stack, action_set_len, + ofpacts_len, ofpacts); + node = recirc_ref_equal(ofproto, table_id, md, stack, action_set_len, + ofpacts_len, ofpacts, hash); + + /* Allocate a new recirc ID if needed. */ + if (!node) { + ovs_assert(action_set_len <= ofpacts_len); + + node = recirc_alloc_id__(ofproto, table_id, md, stack, action_set_len, + ofpacts_len, ofpacts, hash); + } + + return node->id; } +/* Allocate a unique recirculation id. */ uint32_t -recirc_id_alloc(struct recirc_id_pool *pool) +recirc_alloc_id(struct ofproto_dpif *ofproto) { - uint32_t id; - bool ret; + struct recirc_metadata md; + struct recirc_id_node *node; + uint32_t hash; - ovs_mutex_lock(&pool->lock); - ret = id_pool_alloc_id(pool->rids, &id); - ovs_mutex_unlock(&pool->lock); + memset(&md, 0, sizeof md); + md.in_port = OFPP_NONE; + hash = recirc_metadata_hash(ofproto, TBL_INTERNAL, &md, NULL, 0, 0, NULL); + node = recirc_alloc_id__(ofproto, TBL_INTERNAL, &md, NULL, 0, 0, NULL, + hash); + return node->id; +} - if (!ret) { - return 0; +void +recirc_id_node_unref(const struct recirc_id_node *node_) + OVS_EXCLUDED(mutex) +{ + struct recirc_id_node *node = CONST_CAST(struct recirc_id_node *, node_); + + if (node && ovs_refcount_unref(&node->refcount) == 1) { + ovs_mutex_lock(&mutex); + /* Prevent re-use of this node by removing the node from 'metadata_map' + */ + cmap_remove(&metadata_map, &node->metadata_node, node->hash); + /* We keep the node in the 'id_map' so that it can be found as long + * as it lingers, and add it to the 'expiring' list. */ + list_insert(&expiring, &node->exp_node); + ovs_mutex_unlock(&mutex); } +} - return id; +void +recirc_free_id(uint32_t id) +{ + const struct recirc_id_node *node; + + node = recirc_id_node_find(id); + if (node) { + recirc_id_node_unref(node); + } else { + VLOG_ERR("Freeing nonexistent recirculation ID: %"PRIu32, id); + } } +/* Called when 'ofproto' is destructed. Checks for and clears any + * recirc_id leak. + * No other thread may have access to the 'ofproto' being destructed. + * All related datapath flows must be deleted before calling this. */ void -recirc_id_free(struct recirc_id_pool *pool, uint32_t id) +recirc_free_ofproto(struct ofproto_dpif *ofproto, const char *ofproto_name) { - ovs_mutex_lock(&pool->lock); - id_pool_free_id(pool->rids, id); - ovs_mutex_unlock(&pool->lock); + struct recirc_id_node *n; + + CMAP_FOR_EACH (n, metadata_node, &metadata_map) { + if (n->ofproto == ofproto) { + VLOG_ERR("recirc_id %"PRIu32 + " left allocated when ofproto (%s)" + " is destructed", n->id, ofproto_name); + } + } } diff --git a/ofproto/ofproto-dpif-rid.h b/ofproto/ofproto-dpif-rid.h index 3344e2a53..81a61a236 100644 --- a/ofproto/ofproto-dpif-rid.h +++ b/ofproto/ofproto-dpif-rid.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Nicira, Inc. + * Copyright (c) 2014, 2015 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,29 +20,164 @@ #include #include -struct recirc_id_pool; +#include "cmap.h" +#include "list.h" +#include "ofp-actions.h" +#include "ovs-thread.h" + +struct ofproto_dpif; +struct rule; /* - * Recirculation ID pool. - * ====================== + * Recirculation + * ============= + * + * Recirculation is a technique to allow a frame to re-enter the datapath + * packet processing path for one or multiple times to achieve more flexible + * packet processing, such modifying header fields after MPLS POP action and + * selecting bond a slave port for bond ports. + * + * Data path and user space interface + * ----------------------------------- + * + * Recirculation uses two uint32_t fields, recirc_id and dp_hash, and a RECIRC + * action. The value recirc_id is used to select the next packet processing + * steps among multiple instances of recirculation. When a packet initially + * enters the data path it is assigned with recirc_id 0, which indicates no + * recirculation. Recirc_ids are managed by the user space, opaque to the + * data path. + * + * On the other hand, dp_hash can only be computed by the data path, opaque to + * the user space. In fact, user space may not able to recompute the hash + * value. The dp_hash value should be wildcarded for a newly received + * packet. HASH action specifies whether the hash is computed, and if + * computed, how many fields are to be included in the hash computation. The + * computed hash value is stored into the dp_hash field prior to recirculation. + * + * The RECIRC action sets the recirc_id field and then reprocesses the packet + * as if it was received on the same input port. RECIRC action works like a + * function call; actions listed behind the RECIRC action will be executed + * after its execution. RECIRC action can be nested, data path implementation + * limits the number of recirculation executed to prevent unreasonable nesting + * depth or infinite loop. + * + * User space recirculation context + * --------------------------------- * - * Recirculation ID needs to be unique for each datapath. Recirculation - * ID pool keeps track recirculation ids. + * Recirculation is hidden from the OpenFlow controllers. Action translation + * code deduces when recirculation is necessary and issues a data path + * recirculation action. All OpenFlow actions to be performed after + * recirculation are derived from the OpenFlow pipeline and are stored with the + * recirculation ID. When the OpenFlow tables are changed in a way affecting + * the recirculation flows, new recirculation ID with new metadata and actions + * is allocated and the old one is timed out. * - * Typically, there is one recirculation ID pool for each backer. + * Recirculation ID pool + * ---------------------- * - * In theory, Recirculation ID can be any uint32_t value, except 0. - * The implementation usually limits it to a smaller range to ease - * debugging. + * Recirculation ID needs to be unique for all data paths. Recirculation ID + * pool keeps track recirculation ids and stores OpenFlow pipeline translation + * context so that flow processing may continue after recirculation. + * + * A Recirculation ID can be any uint32_t value, except for that the value 0 is + * reserved for 'no recirculation' case. * * Thread-safety - * ============= + * -------------- * * All APIs are thread safe. - * */ -struct recirc_id_pool *recirc_id_pool_create(void); -void recirc_id_pool_destroy(struct recirc_id_pool *pool); -uint32_t recirc_id_alloc(struct recirc_id_pool *pool); -void recirc_id_free(struct recirc_id_pool *pool, uint32_t recirc_id); + +/* Metadata for restoring pipeline context after recirculation. Helpers + * are inlined below to keep them together with the definition for easier + * updates. */ +BUILD_ASSERT_DECL(FLOW_WC_SEQ == 31); + +struct recirc_metadata { + /* Metadata in struct flow. */ + struct flow_tnl tunnel; /* Encapsulating tunnel parameters. */ + ovs_be64 metadata; /* OpenFlow Metadata. */ + uint64_t regs[FLOW_N_XREGS]; /* Registers. */ + ofp_port_t in_port; /* Incoming port. */ + ofp_port_t actset_output; /* Output port in action set. */ +}; + +static inline void +recirc_metadata_from_flow(struct recirc_metadata *md, + const struct flow *flow) +{ + memset(md, 0, sizeof *md); + md->tunnel = flow->tunnel; + md->metadata = flow->metadata; + memcpy(md->regs, flow->regs, sizeof md->regs); + md->in_port = flow->in_port.ofp_port; + md->actset_output = flow->actset_output; +} + +static inline void +recirc_metadata_to_flow(const struct recirc_metadata *md, + struct flow *flow) +{ + flow->tunnel = md->tunnel; + flow->metadata = md->metadata; + memcpy(flow->regs, md->regs, sizeof flow->regs); + flow->in_port.ofp_port = md->in_port; + flow->actset_output = md->actset_output; +} + +/* Pool node fields should NOT be modified after placing the node in the pool. + */ +struct recirc_id_node { + struct ovs_list exp_node OVS_GUARDED; + struct cmap_node id_node; + struct cmap_node metadata_node; + uint32_t id; + uint32_t hash; + struct ovs_refcount refcount; + + /* Initial table for post-recirculation processing. */ + uint8_t table_id; + + /* Pipeline context for post-recirculation processing. */ + struct ofproto_dpif *ofproto; /* Post-recirculation bridge. */ + struct recirc_metadata metadata; /* Flow metadata. */ + struct ofpbuf *stack; /* Stack if any. */ + + /* Actions to be translated on recirculation. */ + uint32_t action_set_len; /* How much of 'ofpacts' consists of an + * action set? */ + uint32_t ofpacts_len; /* Size of 'ofpacts', in bytes. */ + struct ofpact ofpacts[]; /* Sequence of "struct ofpacts". */ +}; + +void recirc_init(void); + +/* This is only used for bonds and will go away when bonds implementation is + * updated to use this mechanism instead of internal rules. */ +uint32_t recirc_alloc_id(struct ofproto_dpif *); + +uint32_t recirc_alloc_id_ctx(struct ofproto_dpif *, uint8_t table_id, + struct recirc_metadata *, struct ofpbuf *stack, + uint32_t action_set_len, uint32_t ofpacts_len, + const struct ofpact *); +uint32_t recirc_find_id(struct ofproto_dpif *, uint8_t table_id, + struct recirc_metadata *, struct ofpbuf *stack, + uint32_t action_set_len, uint32_t ofpacts_len, + const struct ofpact *); +void recirc_free_id(uint32_t recirc_id); +void recirc_free_ofproto(struct ofproto_dpif *, const char *ofproto_name); + +const struct recirc_id_node *recirc_id_node_find(uint32_t recirc_id); + +static inline bool recirc_id_node_try_ref_rcu(const struct recirc_id_node *n_) +{ + struct recirc_id_node *node = CONST_CAST(struct recirc_id_node *, n_); + + return node ? ovs_refcount_try_ref_rcu(&node->refcount) : false; +} + +void recirc_id_node_unref(const struct recirc_id_node *); + +void recirc_run(void); + #endif diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c index 3c80a0c03..01bc382b5 100644 --- a/ofproto/ofproto-dpif-upcall.c +++ b/ofproto/ofproto-dpif-upcall.c @@ -152,6 +152,8 @@ enum upcall_type { struct upcall { struct ofproto_dpif *ofproto; /* Parent ofproto. */ + const struct recirc_id_node *recirc; /* Recirculation context. */ + bool have_recirc_ref; /* Reference held on recirc ctx? */ /* The flow and packet are only required to be constant when using * dpif-netdev. If a modification is absolutely necessary, a const cast @@ -229,6 +231,10 @@ struct udpif_key { struct odputil_keybuf buf; struct nlattr nla; } keybuf, maskbuf; + + /* Recirculation IDs with references held by the ukey. */ + unsigned n_recircs; + uint32_t recircs[]; /* 'n_recircs' id's for which references are held. */ }; /* Datapath operation with optional ukey attached. */ @@ -271,7 +277,7 @@ static void upcall_unixctl_dump_wait(struct unixctl_conn *conn, int argc, static void upcall_unixctl_purge(struct unixctl_conn *conn, int argc, const char *argv[], void *aux); -static struct udpif_key *ukey_create_from_upcall(const struct upcall *); +static struct udpif_key *ukey_create_from_upcall(struct upcall *); static int ukey_create_from_dpif_flow(const struct udpif *, const struct dpif_flow *, struct udpif_key **); @@ -737,6 +743,8 @@ udpif_revalidator(void *arg) if (leader) { uint64_t reval_seq; + recirc_run(); /* Recirculation cleanup. */ + reval_seq = seq_read(udpif->reval_seq); last_reval_seq = reval_seq; @@ -903,6 +911,8 @@ upcall_receive(struct upcall *upcall, const struct dpif_backer *backer, return error; } + upcall->recirc = NULL; + upcall->have_recirc_ref = false; upcall->flow = flow; upcall->packet = packet; upcall->ufid = ufid; @@ -942,9 +952,21 @@ upcall_xlate(struct udpif *udpif, struct upcall *upcall, if (upcall->type == DPIF_UC_MISS) { xin.resubmit_stats = &stats; + + if (xin.recirc) { + /* We may install a datapath flow only if we get a reference to the + * recirculation context (otherwise we could have recirculation + * upcalls using recirculation ID for which no context can be + * found). We may still execute the flow's actions even if we + * don't install the flow. */ + upcall->recirc = xin.recirc; + upcall->have_recirc_ref = recirc_id_node_try_ref_rcu(xin.recirc); + } } else { - /* For non-miss upcalls, there's a flow in the datapath which this - * packet was accounted to. Presumably the revalidators will deal + /* For non-miss upcalls, we are either executing actions (one of which + * is an userspace action) for an upcall, in which case the stats have + * already been taken care of, or there's a flow in the datapath which + * this packet was accounted to. Presumably the revalidators will deal * with pushing its stats eventually. */ } @@ -1005,8 +1027,13 @@ upcall_uninit(struct upcall *upcall) xlate_out_uninit(&upcall->xout); } ofpbuf_uninit(&upcall->put_actions); - if (!upcall->ukey_persists) { - ukey_delete__(upcall->ukey); + if (upcall->ukey) { + if (!upcall->ukey_persists) { + ukey_delete__(upcall->ukey); + } + } else if (upcall->have_recirc_ref) { + /* The reference was transferred to the ukey if one was created. */ + recirc_id_node_unref(upcall->recirc); } } } @@ -1056,10 +1083,16 @@ upcall_cb(const struct dp_packet *packet, const struct flow *flow, ovs_u128 *ufi goto out; } - if (upcall.ukey && !ukey_install(udpif, upcall.ukey)) { + /* Prevent miss flow installation if the key has recirculation ID but we + * were not able to get a reference on it. */ + if (type == DPIF_UC_MISS && upcall.recirc && !upcall.have_recirc_ref) { error = ENOSPC; + goto out; } + if (upcall.ukey && !ukey_install(udpif, upcall.ukey)) { + error = ENOSPC; + } out: if (!error) { upcall.ukey_persists = true; @@ -1189,8 +1222,12 @@ handle_upcalls(struct udpif *udpif, struct upcall *upcalls, * - The datapath already has too many flows. * * - We received this packet via some flow installed in the kernel - * already. */ - if (may_put && upcall->type == DPIF_UC_MISS) { + * already. + * + * - Upcall was a recirculation but we do not have a reference to + * to the recirculation ID. */ + if (may_put && upcall->type == DPIF_UC_MISS && + (!upcall->recirc || upcall->have_recirc_ref)) { struct udpif_key *ukey = upcall->ukey; upcall->ukey_persists = true; @@ -1277,10 +1314,13 @@ ukey_create__(const struct nlattr *key, size_t key_len, const struct nlattr *mask, size_t mask_len, bool ufid_present, const ovs_u128 *ufid, const int pmd_id, const struct ofpbuf *actions, - uint64_t dump_seq, uint64_t reval_seq, long long int used) + uint64_t dump_seq, uint64_t reval_seq, long long int used, + const struct recirc_id_node *key_recirc, struct xlate_out *xout) OVS_NO_THREAD_SAFETY_ANALYSIS { - struct udpif_key *ukey = xmalloc(sizeof *ukey); + unsigned n_recircs = (key_recirc ? 1 : 0) + (xout ? xout->n_recircs : 0); + struct udpif_key *ukey = xmalloc(sizeof *ukey + + n_recircs * sizeof *ukey->recircs); memcpy(&ukey->keybuf, key, key_len); ukey->key = &ukey->keybuf.nla; @@ -1303,11 +1343,22 @@ ukey_create__(const struct nlattr *key, size_t key_len, ukey->stats.used = used; ukey->xcache = NULL; + ukey->n_recircs = n_recircs; + if (key_recirc) { + ukey->recircs[0] = key_recirc->id; + } + if (xout && xout->n_recircs) { + const uint32_t *act_recircs = xlate_out_get_recircs(xout); + + memcpy(ukey->recircs + (key_recirc ? 1 : 0), act_recircs, + xout->n_recircs * sizeof *ukey->recircs); + xlate_out_take_recircs(xout); + } return ukey; } static struct udpif_key * -ukey_create_from_upcall(const struct upcall *upcall) +ukey_create_from_upcall(struct upcall *upcall) { struct odputil_keybuf keystub, maskstub; struct ofpbuf keybuf, maskbuf; @@ -1337,7 +1388,9 @@ ukey_create_from_upcall(const struct upcall *upcall) return ukey_create__(keybuf.data, keybuf.size, maskbuf.data, maskbuf.size, true, upcall->ufid, upcall->pmd_id, &upcall->put_actions, upcall->dump_seq, - upcall->reval_seq, 0); + upcall->reval_seq, 0, + upcall->have_recirc_ref ? upcall->recirc : NULL, + &upcall->xout); } static int @@ -1349,12 +1402,15 @@ ukey_create_from_dpif_flow(const struct udpif *udpif, struct ofpbuf actions; uint64_t dump_seq, reval_seq; uint64_t stub[DPIF_FLOW_BUFSIZE / 8]; + const struct nlattr *a; + unsigned int left; - if (!flow->key_len) { + if (!flow->key_len || !flow->actions_len) { struct ofpbuf buf; int err; - /* If the key was not provided by the datapath, fetch the full flow. */ + /* If the key or actions were not provided by the datapath, fetch the + * full flow. */ ofpbuf_use_stack(&buf, &stub, sizeof stub); err = dpif_flow_get(udpif->dpif, NULL, 0, &flow->ufid, flow->pmd_id, &buf, &full_flow); @@ -1363,13 +1419,23 @@ ukey_create_from_dpif_flow(const struct udpif *udpif, } flow = &full_flow; } + + /* Check the flow actions for recirculation action. As recirculation + * relies on OVS userspace internal state, we need to delete all old + * datapath flows with recirculation upon OVS restart. */ + NL_ATTR_FOR_EACH_UNSAFE (a, left, flow->actions, flow->actions_len) { + if (nl_attr_type(a) == OVS_ACTION_ATTR_RECIRC) { + return EINVAL; + } + } + dump_seq = seq_read(udpif->dump_seq); reval_seq = seq_read(udpif->reval_seq); ofpbuf_use_const(&actions, &flow->actions, flow->actions_len); *ukey = ukey_create__(flow->key, flow->key_len, flow->mask, flow->mask_len, flow->ufid_present, &flow->ufid, flow->pmd_id, &actions, dump_seq, - reval_seq, flow->stats.used); + reval_seq, flow->stats.used, NULL, NULL); return 0; } @@ -1512,6 +1578,9 @@ ukey_delete__(struct udpif_key *ukey) OVS_NO_THREAD_SAFETY_ANALYSIS { if (ukey) { + for (int i = 0; i < ukey->n_recircs; i++) { + recirc_free_id(ukey->recircs[i]); + } xlate_cache_delete(ukey->xcache); ofpbuf_delete(ukey->actions); ovs_mutex_destroy(&ukey->mutex); @@ -1776,8 +1845,8 @@ push_ukey_ops__(struct udpif *udpif, struct ukey_op *ops, size_t n_ops) continue; } - error = xlate_lookup(udpif->backer, &flow, &ofproto, - NULL, NULL, &netflow, &ofp_in_port); + error = xlate_lookup(udpif->backer, &flow, &ofproto, NULL, NULL, + &netflow, &ofp_in_port); if (!error) { struct xlate_in xin; diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index bdb9d538e..3e22a5fa0 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -71,9 +71,6 @@ VLOG_DEFINE_THIS_MODULE(ofproto_dpif_xlate); #define MAX_INTERNAL_RESUBMITS 1 /* Max resbmits allowed using rules in internal table. */ -/* Timeout for internal rules created to handle recirculation */ -#define RECIRC_TIMEOUT 60 - /* Maximum number of resubmit actions in a flow translation, whether they are * recursive or not. */ #define MAX_RESUBMITS (MAX_RESUBMIT_RECURSION * MAX_RESUBMIT_RECURSION) @@ -208,6 +205,91 @@ struct xlate_ctx { uint16_t user_cookie_offset;/* Used for user_action_cookie fixup. */ bool exit; /* No further actions should be processed. */ + /* These are used for non-bond recirculation. The recirculation IDs are + * stored in xout and must be associated with a datapath flow (ukey), + * otherwise they will be freed when the xout is uninitialized. + * + * + * Steps in Recirculation Translation + * ================================== + * + * At some point during translation, the code recognizes the need for + * recirculation. For example, recirculation is necessary when, after + * popping the last MPLS label, an action or a match tries to examine or + * modify a field that has been newly revealed following the MPLS label. + * + * The simplest part of the work to be done is to commit existing changes to + * the packet, which produces datapath actions corresponding to the changes, + * and after this, add an OVS_ACTION_ATTR_RECIRC datapath action. + * + * The main problem here is preserving state. When the datapath executes + * OVS_ACTION_ATTR_RECIRC, it will upcall to userspace to get a translation + * for the post-recirculation actions. At this point userspace has to + * resume the translation where it left off, which means that it has to + * execute the following: + * + * - The action that prompted recirculation, and any actions following + * it within the same flow. + * + * - If the action that prompted recirculation was invoked within a + * NXAST_RESUBMIT, then any actions following the resubmit. These + * "resubmit"s can be nested, so this has to go all the way up the + * control stack. + * + * - The OpenFlow 1.1+ action set. + * + * State that actions and flow table lookups can depend on, such as the + * following, must also be preserved: + * + * - Metadata fields (input port, registers, OF1.1+ metadata, ...). + * + * - Action set, stack + * + * - The table ID and cookie of the flow being translated at each level + * of the control stack (since OFPAT_CONTROLLER actions send these to + * the controller). + * + * Translation allows for the control of this state preservation via these + * members. When a need for recirculation is identified, the translation + * process: + * + * 1. Sets 'recirc_action_offset' to the current size of 'action_set'. The + * action set is part of what needs to be preserved, so this allows the + * action set and the additional state to share the 'action_set' buffer. + * Later steps can tell that setup for recirculation is in progress from + * the nonnegative value of 'recirc_action_offset'. + * + * 2. Sets 'exit' to true to tell later steps that we're exiting from the + * translation process. + * + * 3. Adds an OFPACT_UNROLL_XLATE action to 'action_set'. This action + * holds the current table ID and cookie so that they can be restored + * during a post-recirculation upcall translation. + * + * 4. Adds the action that prompted recirculation and any actions following + * it within the same flow to 'action_set', so that they can be executed + * during a post-recirculation upcall translation. + * + * 5. Returns. + * + * 6. The action that prompted recirculation might be nested in a stack of + * nested "resubmit"s that have actions remaining. Each of these notices + * that we're exiting (from 'exit') and that recirculation setup is in + * progress (from 'recirc_action_offset') and responds by adding more + * OFPACT_UNROLL_XLATE actions to 'action_set', as necessary, and any + * actions that were yet unprocessed. + * + * The caller stores all the state produced by this process associated with + * the recirculation ID. For post-recirculation upcall translation, the + * caller passes it back in for the new translation to execute. The + * process yielded a set of ofpacts that can be translated directly, so it + * is not much of a special case at that point. + */ + int recirc_action_offset; /* Offset in 'action_set' to actions to be + * executed after recirculation, or -1. */ + int last_unroll_offset; /* Offset in 'action_set' to the latest unroll + * action, or -1. */ + /* True if a packet was but is no longer MPLS (due to an MPLS pop action). * This is a trigger for recirculation in cases where translating an action * or looking up a flow requires access to the fields of the packet after @@ -230,6 +312,16 @@ struct xlate_ctx { static void xlate_action_set(struct xlate_ctx *ctx); +static inline bool +exit_recirculates(const struct xlate_ctx *ctx) +{ + /* When recirculating the 'recirc_action_offset' has a non-negative value. + */ + return ctx->recirc_action_offset >= 0; +} + +static void compose_recirculate_action(struct xlate_ctx *ctx); + /* A controller may use OFPP_NONE as the ingress port to indicate that * it did not arrive on a "real" port. 'ofpp_none_bundle' exists for * when an input bundle is needed for validation (e.g., mirroring or @@ -985,64 +1077,24 @@ xlate_ofport_remove(struct ofport_dpif *ofport) xlate_xport_remove(new_xcfg, xport); } -/* Given a datapath and flow metadata ('backer', and 'flow' respectively) - * returns the corresponding struct xport, or NULL if none is found. */ -static struct xport * -xlate_lookup_xport(const struct dpif_backer *backer, const struct flow *flow) -{ - struct xlate_cfg *xcfg = ovsrcu_get(struct xlate_cfg *, &xcfgp); - - return xport_lookup(xcfg, tnl_port_should_receive(flow) - ? tnl_port_receive(flow) - : odp_port_to_ofport(backer, flow->in_port.odp_port)); -} - static struct ofproto_dpif * xlate_lookup_ofproto_(const struct dpif_backer *backer, const struct flow *flow, ofp_port_t *ofp_in_port, const struct xport **xportp) { - struct ofproto_dpif *recv_ofproto = NULL; - struct ofproto_dpif *recirc_ofproto = NULL; + struct xlate_cfg *xcfg = ovsrcu_get(struct xlate_cfg *, &xcfgp); const struct xport *xport; - ofp_port_t in_port = OFPP_NONE; - - *xportp = xport = xlate_lookup_xport(backer, flow); - - if (xport) { - recv_ofproto = xport->xbridge->ofproto; - in_port = xport->ofp_port; - } - /* When recirc_id is set in 'flow', checks whether the ofproto_dpif that - * corresponds to the recirc_id is same as the receiving bridge. If they - * are the same, uses the 'recv_ofproto' and keeps the 'ofp_in_port' as - * assigned. Otherwise, uses the 'recirc_ofproto' that owns recirc_id and - * assigns OFPP_NONE to 'ofp_in_port'. Doing this is in that, the - * recirculated flow must be processced by the ofproto which originates - * the recirculation, and as bridges can only see their own ports, the - * in_port of the 'recv_ofproto' should not be passed to the - * 'recirc_ofproto'. - * - * Admittedly, setting the 'ofp_in_port' to OFPP_NONE limits the - * 'recirc_ofproto' from meaningfully matching on in_port of recirculated - * flow, and should be fixed in the near future. - * - * TODO: Restore the original patch port. - */ - if (recv_ofproto && flow->recirc_id) { - recirc_ofproto = ofproto_dpif_recirc_get_ofproto(backer, - flow->recirc_id); - if (recv_ofproto != recirc_ofproto) { - *xportp = xport = NULL; - in_port = OFPP_NONE; - } + xport = xport_lookup(xcfg, tnl_port_should_receive(flow) + ? tnl_port_receive(flow) + : odp_port_to_ofport(backer, flow->in_port.odp_port)); + if (OVS_UNLIKELY(!xport)) { + return NULL; } - + *xportp = xport; if (ofp_in_port) { - *ofp_in_port = in_port; + *ofp_in_port = xport->ofp_port; } - - return xport ? recv_ofproto : recirc_ofproto; + return xport->xbridge->ofproto; } /* Given a datapath and flow metadata ('backer', and 'flow' respectively) @@ -2741,7 +2793,6 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, struct flow old_flow = ctx->xin->flow; bool old_was_mpls = ctx->was_mpls; enum slow_path_reason special; - uint8_t table_id = rule_dpif_lookup_get_init_table_id(&ctx->xin->flow); struct ofpbuf old_stack = ctx->stack; union mf_subvalue new_stack[1024 / sizeof(union mf_subvalue)]; struct ofpbuf old_action_set = ctx->action_set; @@ -2762,11 +2813,17 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, ctx->xout->slow |= special; } else if (may_receive(peer, ctx)) { if (xport_stp_forward_state(peer) && xport_rstp_forward_state(peer)) { - xlate_table_action(ctx, flow->in_port.ofp_port, table_id, - true, true); + xlate_table_action(ctx, flow->in_port.ofp_port, 0, true, true); if (ctx->action_set.size) { - /* Translate action set only if not dropping the packet. */ - xlate_action_set(ctx); + /* Translate action set only if not dropping the packet and + * not recirculating. */ + if (!exit_recirculates(ctx)) { + xlate_action_set(ctx); + } + } + /* Check if need to recirculate. */ + if (exit_recirculates(ctx)) { + compose_recirculate_action(ctx); } } else { /* Forwarding is disabled by STP and RSTP. Let OFPP_NORMAL and @@ -2775,11 +2832,17 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, size_t old_size = ctx->xout->odp_actions->size; mirror_mask_t old_mirrors = ctx->xout->mirrors; - xlate_table_action(ctx, flow->in_port.ofp_port, table_id, - true, true); + xlate_table_action(ctx, flow->in_port.ofp_port, 0, true, true); ctx->xout->mirrors = old_mirrors; ctx->base_flow = old_base_flow; ctx->xout->odp_actions->size = old_size; + + /* Undo changes that may have been done for recirculation. */ + if (exit_recirculates(ctx)) { + ctx->action_set.size = ctx->recirc_action_offset; + ctx->recirc_action_offset = -1; + ctx->last_unroll_offset = -1; + } } } @@ -3071,6 +3134,11 @@ xlate_group_bucket(struct xlate_ctx *ctx, struct ofputil_bucket *bucket) ofpbuf_uninit(&action_set); ofpbuf_uninit(&action_list); + /* Check if need to recirculate. */ + if (exit_recirculates(ctx)) { + compose_recirculate_action(ctx); + } + /* Roll back flow to previous state. * This is equivalent to cloning the packet for each bucket. * @@ -3392,69 +3460,53 @@ execute_controller_action(struct xlate_ctx *ctx, int len, dp_packet_delete(packet); } +/* Called only when ctx->recirc_action_offset is set. */ static void -compose_recirculate_action(struct xlate_ctx *ctx, - const struct ofpact *ofpacts_base, - const struct ofpact *ofpact_current, - size_t ofpacts_base_len) +compose_recirculate_action(struct xlate_ctx *ctx) { + struct recirc_metadata md; uint32_t id; - int error; - unsigned ofpacts_len; - struct match match; - struct rule *rule; - struct ofpbuf ofpacts; - ctx->exit = true; + ctx->xout->slow |= commit_odp_actions(&ctx->xin->flow, &ctx->base_flow, + ctx->xout->odp_actions, + &ctx->xout->wc, + ctx->xbridge->masked_set_action); - ofpacts_len = ofpacts_base_len - - ((uint8_t *)ofpact_current - (uint8_t *)ofpacts_base); + recirc_metadata_from_flow(&md, &ctx->xin->flow); - if (ctx->rule) { - id = rule_dpif_get_recirc_id(ctx->rule); - } else { - /* In the case where ctx has no rule then allocate a recirc id. - * The life-cycle of this recirc id is managed by associating it - * with the internal rule that is created to to handle - * recirculation below. - * - * The known use-case of this is packet_out which - * translates actions without a rule */ - id = ofproto_dpif_alloc_recirc_id(ctx->xbridge->ofproto); - } - if (!id) { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); - VLOG_ERR_RL(&rl, "Failed to allocate recirculation id"); - return; - } + ovs_assert(ctx->recirc_action_offset >= 0); - match_init_catchall(&match); - match_set_recirc_id(&match, id); - ofpbuf_use_const(&ofpacts, ofpact_current, ofpacts_len); - error = ofproto_dpif_add_internal_flow(ctx->xbridge->ofproto, &match, - RECIRC_RULE_PRIORITY, - RECIRC_TIMEOUT, &ofpacts, &rule); - if (error) { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); - VLOG_ERR_RL(&rl, "Failed to add post recirculation flow %s", - match_to_string(&match, 0)); - if (!ctx->rule) { - ofproto_dpif_free_recirc_id(ctx->xbridge->ofproto, id); + /* Only allocate recirculation ID if we have a packet. */ + if (ctx->xin->packet) { + /* Allocate a unique recirc id for the given metadata state in the + * flow. The life-cycle of this recirc id is managed by associating it + * with the udpif key ('ukey') created for each new datapath flow. */ + id = recirc_alloc_id_ctx(ctx->xbridge->ofproto, 0, &md, &ctx->stack, + ctx->recirc_action_offset, + ctx->action_set.size, ctx->action_set.data); + if (!id) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + VLOG_ERR_RL(&rl, "Failed to allocate recirculation id"); + return; } - return; - } - /* If ctx has no rule then associate the recirc id, which - * was allocated above, with the internal rule. This allows - * the recirc id to be released when the internal rule times out. */ - if (!ctx->rule) { - rule_set_recirc_id(rule, id); + xlate_out_add_recirc(ctx->xout, id); + } else { + /* Look up an existing recirc id for the given metadata state in the + * flow. No new reference is taken, as the ID is RCU protected and is + * only required temporarily for verification. */ + id = recirc_find_id(ctx->xbridge->ofproto, 0, &md, &ctx->stack, + ctx->recirc_action_offset, + ctx->action_set.size, ctx->action_set.data); + /* We let zero 'id' to be used in the RECIRC action below, which will + * fail all revalidations as zero is not a valid recirculation ID. */ } - ctx->xout->slow |= commit_odp_actions(&ctx->xin->flow, &ctx->base_flow, - ctx->xout->odp_actions, - &ctx->xout->wc, - ctx->xbridge->masked_set_action); nl_msg_put_u32(ctx->xout->odp_actions, OVS_ACTION_ATTR_RECIRC, id); + + /* Undo changes done by recirculation. */ + ctx->action_set.size = ctx->recirc_action_offset; + ctx->recirc_action_offset = -1; + ctx->last_unroll_offset = -1; } static void @@ -3935,6 +3987,7 @@ ofpact_needs_recirculation_after_mpls(const struct ofpact *a, struct xlate_ctx * case OFPACT_POP_QUEUE: case OFPACT_CONJUNCTION: case OFPACT_NOTE: + case OFPACT_UNROLL_XLATE: case OFPACT_OUTPUT_REG: case OFPACT_EXIT: case OFPACT_METER: @@ -3987,6 +4040,104 @@ ofpact_needs_recirculation_after_mpls(const struct ofpact *a, struct xlate_ctx * OVS_NOT_REACHED(); } +static void +recirc_put_unroll_xlate(struct xlate_ctx *ctx) +{ + struct ofpact_unroll_xlate *unroll; + + unroll = ctx->last_unroll_offset < 0 + ? NULL + : ALIGNED_CAST(struct ofpact_unroll_xlate *, + (char *)ctx->action_set.data + ctx->last_unroll_offset); + + /* Restore the table_id and rule cookie for a potential PACKET + * IN if needed. */ + if (!unroll || + (ctx->table_id != unroll->rule_table_id + || ctx->rule_cookie != unroll->rule_cookie)) { + + ctx->last_unroll_offset = ctx->action_set.size; + unroll = ofpact_put_UNROLL_XLATE(&ctx->action_set); + unroll->rule_table_id = ctx->table_id; + unroll->rule_cookie = ctx->rule_cookie; + } +} + + +/* Copy remaining actions to the action_set to be executed after recirculation. + * UNROLL_XLATE action is inserted, if not already done so, before actions that + * may generate PACKET_INs from the current table and without matching another + * rule. */ +static void +recirc_unroll_actions(const struct ofpact *ofpacts, size_t ofpacts_len, + struct xlate_ctx *ctx) +{ + const struct ofpact *a; + + OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) { + switch (a->type) { + /* May generate PACKET INs. */ + case OFPACT_OUTPUT_REG: + case OFPACT_GROUP: + case OFPACT_OUTPUT: + case OFPACT_CONTROLLER: + case OFPACT_DEC_MPLS_TTL: + case OFPACT_DEC_TTL: + recirc_put_unroll_xlate(ctx); + break; + + /* These may not generate PACKET INs. */ + case OFPACT_SET_TUNNEL: + case OFPACT_REG_MOVE: + case OFPACT_SET_FIELD: + case OFPACT_STACK_PUSH: + case OFPACT_STACK_POP: + case OFPACT_LEARN: + case OFPACT_WRITE_METADATA: + case OFPACT_RESUBMIT: /* May indirectly generate PACKET INs, */ + case OFPACT_GOTO_TABLE: /* but from a different table and rule. */ + case OFPACT_ENQUEUE: + case OFPACT_SET_VLAN_VID: + case OFPACT_SET_VLAN_PCP: + case OFPACT_STRIP_VLAN: + case OFPACT_PUSH_VLAN: + case OFPACT_SET_ETH_SRC: + case OFPACT_SET_ETH_DST: + case OFPACT_SET_IPV4_SRC: + case OFPACT_SET_IPV4_DST: + case OFPACT_SET_IP_DSCP: + case OFPACT_SET_IP_ECN: + case OFPACT_SET_IP_TTL: + case OFPACT_SET_L4_SRC_PORT: + case OFPACT_SET_L4_DST_PORT: + case OFPACT_SET_QUEUE: + case OFPACT_POP_QUEUE: + case OFPACT_PUSH_MPLS: + case OFPACT_POP_MPLS: + case OFPACT_SET_MPLS_LABEL: + case OFPACT_SET_MPLS_TC: + case OFPACT_SET_MPLS_TTL: + case OFPACT_MULTIPATH: + case OFPACT_BUNDLE: + case OFPACT_EXIT: + case OFPACT_UNROLL_XLATE: + case OFPACT_FIN_TIMEOUT: + case OFPACT_CLEAR_ACTIONS: + case OFPACT_WRITE_ACTIONS: + case OFPACT_METER: + case OFPACT_SAMPLE: + break; + + /* These need not be copied for restoration. */ + case OFPACT_NOTE: + case OFPACT_CONJUNCTION: + continue; + } + /* Copy the action over. */ + ofpbuf_put(&ctx->action_set, a, OFPACT_ALIGN(a->len)); + } +} + static void do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, struct xlate_ctx *ctx) @@ -4006,13 +4157,21 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, const struct ofpact_set_field *set_field; const struct mf_field *mf; - if (ctx->exit) { - break; + if (!ctx->exit && ofpact_needs_recirculation_after_mpls(a, ctx)) { + ctx->exit = true; + ctx->recirc_action_offset = ctx->action_set.size; } - if (ofpact_needs_recirculation_after_mpls(a, ctx)) { - compose_recirculate_action(ctx, ofpacts, a, ofpacts_len); - return; + if (ctx->exit) { + /* Check if need to store the remaining actions for later + * execution. */ + if (exit_recirculates(ctx)) { + recirc_unroll_actions(a, OFPACT_ALIGN(ofpacts_len - + ((uint8_t *)a - + (uint8_t *)ofpacts)), + ctx); + } + break; } switch (a->type) { @@ -4261,6 +4420,14 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, ctx->exit = true; break; + case OFPACT_UNROLL_XLATE: { + struct ofpact_unroll_xlate *unroll = ofpact_get_UNROLL_XLATE(a); + + /* Restore translation context data that was stored earlier. */ + ctx->table_id = unroll->rule_table_id; + ctx->rule_cookie = unroll->rule_cookie; + break; + } case OFPACT_FIN_TIMEOUT: memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto); ctx->xout->has_fin_timeout = true; @@ -4330,13 +4497,21 @@ xlate_in_init(struct xlate_in *xin, struct ofproto_dpif *ofproto, xin->resubmit_stats = NULL; xin->skip_wildcards = false; xin->odp_actions = NULL; + + /* Do recirc lookup. */ + xin->recirc = flow->recirc_id + ? recirc_id_node_find(flow->recirc_id) + : NULL; } void xlate_out_uninit(struct xlate_out *xout) { - if (xout && xout->odp_actions == &xout->odp_actions_buf) { - ofpbuf_uninit(xout->odp_actions); + if (xout) { + if (xout->odp_actions == &xout->odp_actions_buf) { + ofpbuf_uninit(xout->odp_actions); + } + xlate_out_free_recircs(xout); } } @@ -4498,9 +4673,8 @@ too_many_output_actions(const struct ofpbuf *odp_actions OVS_UNUSED) #endif } -/* Translates the 'ofpacts_len' bytes of "struct ofpacts" starting at 'ofpacts' - * into datapath actions in 'odp_actions', using 'ctx'. - * +/* Translates the flow, actions, or rule in 'xin' into datapath actions in + * 'xout'. * The caller must take responsibility for eventually freeing 'xout', with * xlate_out_uninit(). */ void @@ -4513,6 +4687,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) enum slow_path_reason special; const struct ofpact *ofpacts; + struct xbridge *xbridge; struct xport *in_port; struct flow orig_flow; struct xlate_ctx ctx; @@ -4551,6 +4726,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) ctx.xout->has_fin_timeout = false; ctx.xout->nf_output_iface = NF_OUT_DROP; ctx.xout->mirrors = 0; + ctx.xout->n_recircs = 0; xout->odp_actions = xin->odp_actions; if (!xout->odp_actions) { @@ -4560,10 +4736,13 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) } ofpbuf_reserve(xout->odp_actions, NL_A_U32_SIZE); - ctx.xbridge = xbridge_lookup(xcfg, xin->ofproto); - if (!ctx.xbridge) { + xbridge = xbridge_lookup(xcfg, xin->ofproto); + if (!xbridge) { return; } + /* 'ctx.xbridge' may be changed by action processing, whereas 'xbridge' + * will remain set on the original input bridge. */ + ctx.xbridge = xbridge; ctx.rule = xin->rule; ctx.base_flow = *flow; @@ -4578,12 +4757,12 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) if (is_ip_any(flow)) { wc->masks.nw_frag |= FLOW_NW_FRAG_MASK; } - if (ctx.xbridge->enable_recirc) { + if (xbridge->enable_recirc) { /* Always exactly match recirc_id when datapath supports * recirculation. */ wc->masks.recirc_id = UINT32_MAX; } - if (ctx.xbridge->netflow) { + if (xbridge->netflow) { netflow_mask_wc(flow, wc); } } @@ -4600,11 +4779,96 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) ctx.rule_cookie = OVS_BE64_MAX; ctx.exit = false; ctx.was_mpls = false; + ctx.recirc_action_offset = -1; + ctx.last_unroll_offset = -1; + + ctx.action_set_has_group = false; + ofpbuf_use_stub(&ctx.action_set, + ctx.action_set_stub, sizeof ctx.action_set_stub); + + ofpbuf_use_stub(&ctx.stack, ctx.init_stack, sizeof ctx.init_stack); + + /* The in_port of the original packet before recirculation. */ + in_port = get_ofp_port(xbridge, flow->in_port.ofp_port); + + if (xin->recirc) { + const struct recirc_id_node *recirc = xin->recirc; + + if (xin->ofpacts_len > 0 || ctx.rule) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); + + VLOG_WARN_RL(&rl, "Recirculation conflict (%s)!", + xin->ofpacts_len > 0 + ? "actions" + : "rule"); + return; + } + + /* Set the bridge for post-recirculation processing if needed. */ + if (ctx.xbridge->ofproto != recirc->ofproto) { + struct xlate_cfg *xcfg = ovsrcu_get(struct xlate_cfg *, &xcfgp); + const struct xbridge *new_bridge = xbridge_lookup(xcfg, + recirc->ofproto); + + if (OVS_UNLIKELY(!new_bridge)) { + /* Drop the packet if the bridge cannot be found. */ + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); + VLOG_WARN_RL(&rl, "Recirculation bridge no longer exists."); + return; + } + ctx.xbridge = new_bridge; + } + + /* Set the post-recirculation table id. Note: A table lookup is done + * only if there are no post-recirculation actions. */ + ctx.table_id = recirc->table_id; + + /* Restore pipeline metadata. May change flow's in_port and other + * metadata to the values that existed when recirculation was + * triggered. */ + recirc_metadata_to_flow(&recirc->metadata, flow); + + /* Restore stack, if any. */ + if (recirc->stack) { + ofpbuf_put(&ctx.stack, recirc->stack->data, recirc->stack->size); + } + + /* Restore action set, if any. */ + if (recirc->action_set_len) { + const struct ofpact *a; + + ofpbuf_put(&ctx.action_set, recirc->ofpacts, + recirc->action_set_len); + + OFPACT_FOR_EACH(a, recirc->ofpacts, recirc->action_set_len) { + if (a->type == OFPACT_GROUP) { + ctx.action_set_has_group = true; + break; + } + } + } + + /* Restore recirculation actions. If there are no actions, processing + * will start with a lookup in the table set above. */ + if (recirc->ofpacts_len > recirc->action_set_len) { + xin->ofpacts_len = recirc->ofpacts_len - recirc->action_set_len; + xin->ofpacts = recirc->ofpacts + + recirc->action_set_len / sizeof *recirc->ofpacts; + } + } else if (OVS_UNLIKELY(flow->recirc_id)) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); + + VLOG_WARN_RL(&rl, "Recirculation context not found for ID %"PRIx32, + flow->recirc_id); + return; + } if (!xin->ofpacts && !ctx.rule) { - rule = rule_dpif_lookup(ctx.xbridge->ofproto, flow, wc, - ctx.xin->xcache != NULL, - ctx.xin->resubmit_stats, &ctx.table_id); + rule = rule_dpif_lookup_from_table(ctx.xbridge->ofproto, flow, wc, + ctx.xin->xcache != NULL, + ctx.xin->resubmit_stats, + &ctx.table_id, + flow->in_port.ofp_port, true, true); if (ctx.xin->resubmit_stats) { rule_dpif_credit_stats(rule, ctx.xin->resubmit_stats); } @@ -4636,20 +4900,14 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) OVS_NOT_REACHED(); } - ofpbuf_use_stub(&ctx.stack, ctx.init_stack, sizeof ctx.init_stack); - - ctx.action_set_has_group = false; - ofpbuf_use_stub(&ctx.action_set, - ctx.action_set_stub, sizeof ctx.action_set_stub); - - if (mbridge_has_mirrors(ctx.xbridge->mbridge)) { + if (mbridge_has_mirrors(xbridge->mbridge)) { /* Do this conditionally because the copy is expensive enough that it * shows up in profiles. */ orig_flow = *flow; } - in_port = get_ofp_port(ctx.xbridge, flow->in_port.ofp_port); - if (in_port && in_port->is_tunnel) { + /* Tunnel stats only for non-recirculated packets. */ + if (!xin->recirc && in_port && in_port->is_tunnel) { if (ctx.xin->resubmit_stats) { netdev_vport_inc_rx(in_port->netdev, ctx.xin->resubmit_stats); if (in_port->bfd) { @@ -4665,22 +4923,29 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) } } - special = process_special(&ctx, flow, in_port, ctx.xin->packet); - if (special) { + /* Do not perform special processing on recirculated packets, + * as recirculated packets are not really received by the bridge. */ + if (!xin->recirc && + (special = process_special(&ctx, flow, in_port, ctx.xin->packet))) { ctx.xout->slow |= special; } else { size_t sample_actions_len; if (flow->in_port.ofp_port - != vsp_realdev_to_vlandev(ctx.xbridge->ofproto, + != vsp_realdev_to_vlandev(xbridge->ofproto, flow->in_port.ofp_port, flow->vlan_tci)) { ctx.base_flow.vlan_tci = 0; } - add_sflow_action(&ctx); - add_ipfix_action(&ctx); - sample_actions_len = ctx.xout->odp_actions->size; + /* Sampling is done only for packets really received by the bridge. */ + if (!xin->recirc) { + add_sflow_action(&ctx); + add_ipfix_action(&ctx); + sample_actions_len = ctx.xout->odp_actions->size; + } else { + sample_actions_len = 0; + } if (tnl_may_send && (!in_port || may_receive(in_port, &ctx))) { do_xlate_actions(ofpacts, ofpacts_len, &ctx); @@ -4691,21 +4956,40 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) !xport_rstp_forward_state(in_port))) { /* Drop all actions added by do_xlate_actions() above. */ ctx.xout->odp_actions->size = sample_actions_len; + + /* Undo changes that may have been done for recirculation. */ + if (exit_recirculates(&ctx)) { + ctx.action_set.size = ctx.recirc_action_offset; + ctx.recirc_action_offset = -1; + ctx.last_unroll_offset = -1; + } } else if (ctx.action_set.size) { - /* Translate action set only if not dropping the packet. */ - xlate_action_set(&ctx); + /* Translate action set only if not dropping the packet and + * not recirculating. */ + if (!exit_recirculates(&ctx)) { + xlate_action_set(&ctx); + } + } + /* Check if need to recirculate. */ + if (exit_recirculates(&ctx)) { + compose_recirculate_action(&ctx); } } - if (ctx.xbridge->has_in_band + /* Output only fully processed packets. */ + if (!exit_recirculates(&ctx) + && xbridge->has_in_band && in_band_must_output_to_local_port(flow) && !actions_output_to_local_port(&ctx)) { compose_output_action(&ctx, OFPP_LOCAL, NULL); } - fix_sflow_action(&ctx); - - if (mbridge_has_mirrors(ctx.xbridge->mbridge)) { + if (!xin->recirc) { + fix_sflow_action(&ctx); + } + /* Only mirror fully processed packets. */ + if (!exit_recirculates(&ctx) + && mbridge_has_mirrors(xbridge->mbridge)) { add_mirror_actions(&ctx, &orig_flow); } } @@ -4722,9 +5006,10 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) ctx.xout->slow |= SLOW_ACTION; } - if (mbridge_has_mirrors(ctx.xbridge->mbridge)) { + /* Update mirror stats only for packets really received by the bridge. */ + if (!xin->recirc && mbridge_has_mirrors(xbridge->mbridge)) { if (ctx.xin->resubmit_stats) { - mirror_update_stats(ctx.xbridge->mbridge, xout->mirrors, + mirror_update_stats(xbridge->mbridge, xout->mirrors, ctx.xin->resubmit_stats->n_packets, ctx.xin->resubmit_stats->n_bytes); } @@ -4732,12 +5017,13 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) struct xc_entry *entry; entry = xlate_cache_add_entry(ctx.xin->xcache, XC_MIRROR); - entry->u.mirror.mbridge = mbridge_ref(ctx.xbridge->mbridge); + entry->u.mirror.mbridge = mbridge_ref(xbridge->mbridge); entry->u.mirror.mirrors = xout->mirrors; } } - if (ctx.xbridge->netflow) { + /* Do netflow only for packets really received by the bridge. */ + if (!xin->recirc && xbridge->netflow) { /* Only update netflow if we don't have controller flow. We don't * report NetFlow expiration messages for such facets because they * are just part of the control logic for the network, not real @@ -4746,7 +5032,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) || ofpacts->type != OFPACT_CONTROLLER || ofpact_next(ofpacts) < ofpact_end(ofpacts, ofpacts_len)) { if (ctx.xin->resubmit_stats) { - netflow_flow_update(ctx.xbridge->netflow, flow, + netflow_flow_update(xbridge->netflow, flow, xout->nf_output_iface, ctx.xin->resubmit_stats); } @@ -4754,7 +5040,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) struct xc_entry *entry; entry = xlate_cache_add_entry(ctx.xin->xcache, XC_NETFLOW); - entry->u.nf.netflow = netflow_ref(ctx.xbridge->netflow); + entry->u.nf.netflow = netflow_ref(xbridge->netflow); entry->u.nf.flow = xmemdup(flow, sizeof *flow); entry->u.nf.iface = xout->nf_output_iface; } diff --git a/ofproto/ofproto-dpif-xlate.h b/ofproto/ofproto-dpif-xlate.h index 3e596fb54..6c8ade308 100644 --- a/ofproto/ofproto-dpif-xlate.h +++ b/ofproto/ofproto-dpif-xlate.h @@ -21,6 +21,7 @@ #include "odp-util.h" #include "ofpbuf.h" #include "ofproto-dpif-mirror.h" +#include "ofproto-dpif-rid.h" #include "ofproto-dpif.h" #include "ofproto.h" #include "stp.h" @@ -54,11 +55,72 @@ struct xlate_out { ofp_port_t nf_output_iface; /* Output interface index for NetFlow. */ mirror_mask_t mirrors; /* Bitmap of associated mirrors. */ + /* Recirculation IDs on which references are held. */ + unsigned n_recircs; + union { + uint32_t recirc[2]; /* When n_recircs == 1 or 2 */ + uint32_t *recircs; /* When 'n_recircs' > 2 */ + }; + uint64_t odp_actions_stub[256 / 8]; struct ofpbuf odp_actions_buf; struct ofpbuf *odp_actions; }; +/* Helpers to abstract the recirculation union away. */ +static inline void +xlate_out_add_recirc(struct xlate_out *xout, uint32_t id) +{ + if (OVS_LIKELY(xout->n_recircs < ARRAY_SIZE(xout->recirc))) { + xout->recirc[xout->n_recircs++] = id; + } else { + if (xout->n_recircs == ARRAY_SIZE(xout->recirc)) { + uint32_t *recircs = xmalloc(sizeof xout->recirc + sizeof id); + + memcpy(recircs, xout->recirc, sizeof xout->recirc); + xout->recircs = recircs; + } else { + xout->recircs = xrealloc(xout->recircs, + (xout->n_recircs + 1) * sizeof id); + } + xout->recircs[xout->n_recircs++] = id; + } +} + +static inline const uint32_t * +xlate_out_get_recircs(const struct xlate_out *xout) +{ + if (OVS_LIKELY(xout->n_recircs <= ARRAY_SIZE(xout->recirc))) { + return xout->recirc; + } else { + return xout->recircs; + } +} + +static inline void +xlate_out_take_recircs(struct xlate_out *xout) +{ + if (OVS_UNLIKELY(xout->n_recircs > ARRAY_SIZE(xout->recirc))) { + free(xout->recircs); + } + xout->n_recircs = 0; +} + +static inline void +xlate_out_free_recircs(struct xlate_out *xout) +{ + if (OVS_LIKELY(xout->n_recircs <= ARRAY_SIZE(xout->recirc))) { + for (int i = 0; i < xout->n_recircs; i++) { + recirc_free_id(xout->recirc[i]); + } + } else { + for (int i = 0; i < xout->n_recircs; i++) { + recirc_free_id(xout->recircs[i]); + } + free(xout->recircs); + } +} + struct xlate_in { struct ofproto_dpif *ofproto; @@ -137,6 +199,10 @@ struct xlate_in { * odp_actions stored in xlate_out. If NULL, the default buffer will be * used. */ struct ofpbuf *odp_actions; + + /* The recirculation context related to this translation, as returned by + * xlate_lookup. */ + const struct recirc_id_node *recirc; }; void xlate_ofproto_set(struct ofproto_dpif *, const char *name, struct dpif *, diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index d6a4d8ccb..64024044a 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -255,13 +255,6 @@ COVERAGE_DEFINE(rev_flow_table); COVERAGE_DEFINE(rev_mac_learning); COVERAGE_DEFINE(rev_mcast_snooping); -/* Stores mapping between 'recirc_id' and 'ofproto-dpif'. */ -struct dpif_backer_recirc_node { - struct cmap_node cmap_node; - struct ofproto_dpif *ofproto; - uint32_t recirc_id; -}; - /* All datapaths of a given type share a single dpif backer instance. */ struct dpif_backer { char *type; @@ -279,9 +272,6 @@ struct dpif_backer { bool recv_set_enable; /* Enables or disables receiving packets. */ /* Recirculation. */ - struct recirc_id_pool *rid_pool; /* Recirculation ID pool. */ - struct cmap recirc_map; /* Map of 'recirc_id's to 'ofproto's. */ - struct ovs_mutex recirc_mutex; /* Protects 'recirc_map'. */ bool enable_recirc; /* True if the datapath supports recirculation */ /* True if the datapath supports unique flow identifiers */ @@ -395,8 +385,6 @@ ofproto_dpif_get_enable_ufid(struct dpif_backer *backer) return backer->enable_ufid; } -static struct ofport_dpif *get_ofp_port(const struct ofproto_dpif *ofproto, - ofp_port_t ofp_port); static void ofproto_trace(struct ofproto_dpif *, struct flow *, const struct dp_packet *packet, const struct ofpact[], size_t ofpacts_len, @@ -857,27 +845,6 @@ dealloc(struct ofproto *ofproto_) free(ofproto); } -/* Called when 'ofproto' is destructed. Checks for and clears any - * recirc_id leak. */ -static void -dpif_backer_recirc_clear_ofproto(struct dpif_backer *backer, - struct ofproto_dpif *ofproto) -{ - struct dpif_backer_recirc_node *node; - - ovs_mutex_lock(&backer->recirc_mutex); - CMAP_FOR_EACH (node, cmap_node, &backer->recirc_map) { - if (node->ofproto == ofproto) { - VLOG_ERR("recirc_id %"PRIu32", not freed when ofproto (%s) " - "is destructed", node->recirc_id, ofproto->up.name); - cmap_remove(&backer->recirc_map, &node->cmap_node, - node->recirc_id); - ovsrcu_postpone(free, node); - } - } - ovs_mutex_unlock(&backer->recirc_mutex); -} - static void close_dpif_backer(struct dpif_backer *backer) { @@ -893,9 +860,6 @@ close_dpif_backer(struct dpif_backer *backer) ovs_rwlock_destroy(&backer->odp_to_ofport_lock); hmap_destroy(&backer->odp_to_ofport_map); shash_find_and_delete(&all_dpif_backers, backer->type); - recirc_id_pool_destroy(backer->rid_pool); - cmap_destroy(&backer->recirc_map); - ovs_mutex_destroy(&backer->recirc_mutex); free(backer->type); free(backer->dp_version_string); dpif_close(backer->dpif); @@ -929,6 +893,8 @@ open_dpif_backer(const char *type, struct dpif_backer **backerp) const char *name; int error; + recirc_init(); + backer = shash_find_data(&all_dpif_backers, type); if (backer) { backer->refcount++; @@ -1010,9 +976,6 @@ open_dpif_backer(const char *type, struct dpif_backer **backerp) backer->max_mpls_depth = check_max_mpls_depth(backer); backer->masked_set_action = check_masked_set_action(backer); backer->enable_ufid = check_ufid(backer); - backer->rid_pool = recirc_id_pool_create(); - ovs_mutex_init(&backer->recirc_mutex); - cmap_init(&backer->recirc_map); backer->enable_tnl_push_pop = dpif_supports_tnl_push_pop(backer->dpif); atomic_count_init(&backer->tnl_count, 0); @@ -1365,7 +1328,6 @@ add_internal_flows(struct ofproto_dpif *ofproto) uint64_t ofpacts_stub[128 / 8]; struct ofpbuf ofpacts; struct rule *unused_rulep OVS_UNUSED; - struct ofpact_resubmit *resubmit; struct match match; int error; int id; @@ -1408,22 +1370,6 @@ add_internal_flows(struct ofproto_dpif *ofproto) match_set_recirc_id(&match, 0); error = ofproto_dpif_add_internal_flow(ofproto, &match, 2, 0, &ofpacts, &unused_rulep); - if (error) { - return error; - } - - /* Continue rule lookups for not-matched recirc rules from table 0. - * - * (priority=1), actions=resubmit(, 0) - */ - resubmit = ofpact_put_RESUBMIT(&ofpacts); - resubmit->in_port = OFPP_IN_PORT; - resubmit->table_id = 0; - - match_init_catchall(&match); - error = ofproto_dpif_add_internal_flow(ofproto, &match, 1, 0, &ofpacts, - &unused_rulep); - return error; } @@ -1461,7 +1407,7 @@ destruct(struct ofproto *ofproto_) } guarded_list_destroy(&ofproto->pins); - dpif_backer_recirc_clear_ofproto(ofproto->backer, ofproto); + recirc_free_ofproto(ofproto, ofproto->up.name); mbridge_unref(ofproto->mbridge); @@ -2743,7 +2689,7 @@ bundle_add_port(struct ofbundle *bundle, ofp_port_t ofp_port, { struct ofport_dpif *port; - port = get_ofp_port(bundle->ofproto, ofp_port); + port = ofp_port_to_ofport(bundle->ofproto, ofp_port); if (!port) { return false; } @@ -3249,8 +3195,8 @@ set_mcast_snooping_port(struct ofproto *ofproto_, void *aux, /* Ports. */ -static struct ofport_dpif * -get_ofp_port(const struct ofproto_dpif *ofproto, ofp_port_t ofp_port) +struct ofport_dpif * +ofp_port_to_ofport(const struct ofproto_dpif *ofproto, ofp_port_t ofp_port) { struct ofport *ofport = ofproto_get_port(&ofproto->up, ofp_port); return ofport ? ofport_dpif_cast(ofport) : NULL; @@ -3444,7 +3390,7 @@ static int port_del(struct ofproto *ofproto_, ofp_port_t ofp_port) { struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_); - struct ofport_dpif *ofport = get_ofp_port(ofproto, ofp_port); + struct ofport_dpif *ofport = ofp_port_to_ofport(ofproto, ofp_port); int error = 0; if (!ofport) { @@ -3756,21 +3702,13 @@ static void rule_dpif_set_recirc_id(struct rule_dpif *rule, uint32_t id) OVS_REQUIRES(rule->up.mutex) { - ovs_assert(!rule->recirc_id); - rule->recirc_id = id; -} - -/* Returns 'rule''s recirculation id. */ -uint32_t -rule_dpif_get_recirc_id(struct rule_dpif *rule) - OVS_REQUIRES(rule->up.mutex) -{ - if (!rule->recirc_id) { - struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto); - - rule_dpif_set_recirc_id(rule, ofproto_dpif_alloc_recirc_id(ofproto)); + ovs_assert(!rule->recirc_id || rule->recirc_id == id); + if (rule->recirc_id == id) { + /* Release the new reference to the same id. */ + recirc_free_id(id); + } else { + rule->recirc_id = id; } - return rule->recirc_id; } /* Sets 'rule''s recirculation id. */ @@ -3784,32 +3722,6 @@ rule_set_recirc_id(struct rule *rule_, uint32_t id) ovs_mutex_unlock(&rule->up.mutex); } -/* Lookup 'flow' in table 0 of 'ofproto''s classifier. - * If 'wc' is non-null, sets the fields that were relevant as part of - * the lookup. Returns the table id where a match or miss occurred via - * 'table_id'. This will be zero unless there was a miss and - * OFPTC11_TABLE_MISS_CONTINUE is in effect for the sequence of tables - * where misses occur, or TBL_INTERNAL if the rule has a non-zero - * recirculation ID, and a match was found in the internal table, or if - * there was no match and one of the special rules (drop_frags_rule, - * miss_rule, or no_packet_in_rule) was returned. - * - * The return value is the found rule, which is valid at least until the next - * RCU quiescent period. If the rule needs to stay around longer, - * a non-zero 'take_ref' must be passed in to cause a reference to be taken - * on it before this returns. */ -struct rule_dpif * -rule_dpif_lookup(struct ofproto_dpif *ofproto, struct flow *flow, - struct flow_wildcards *wc, bool take_ref, - const struct dpif_flow_stats *stats, uint8_t *table_id) -{ - *table_id = rule_dpif_lookup_get_init_table_id(flow); - - return rule_dpif_lookup_from_table(ofproto, flow, wc, take_ref, stats, - table_id, flow->in_port.ofp_port, true, - true); -} - /* The returned rule (if any) is valid at least until the next RCU quiescent * period. If the rule needs to stay around longer, a non-zero 'take_ref' * must be passed in to cause a reference to be taken on it. @@ -3943,7 +3855,7 @@ rule_dpif_lookup_from_table(struct ofproto_dpif *ofproto, struct flow *flow, || miss_config == OFPUTIL_TABLE_MISS_CONTROLLER) { struct ofport_dpif *port; - port = get_ofp_port(ofproto, old_in_port); + port = ofp_port_to_ofport(ofproto, old_in_port); if (!port) { VLOG_WARN_RL(&rl, "packet-in on unknown OpenFlow port %"PRIu16, old_in_port); @@ -4034,9 +3946,7 @@ rule_destruct(struct rule *rule_) ovs_mutex_destroy(&rule->stats_mutex); if (rule->recirc_id) { - struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto); - - ofproto_dpif_free_recirc_id(ofproto, rule->recirc_id); + recirc_free_id(rule->recirc_id); } } @@ -5476,7 +5386,7 @@ vsp_add(struct ofport_dpif *port, ofp_port_t realdev_ofp_port, int vid) static odp_port_t ofp_port_to_odp_port(const struct ofproto_dpif *ofproto, ofp_port_t ofp_port) { - const struct ofport_dpif *ofport = get_ofp_port(ofproto, ofp_port); + const struct ofport_dpif *ofport = ofp_port_to_ofport(ofproto, ofp_port); return ofport ? ofport->odp_port : ODPP_NONE; } @@ -5511,61 +5421,6 @@ odp_port_to_ofp_port(const struct ofproto_dpif *ofproto, odp_port_t odp_port) } } -struct ofproto_dpif * -ofproto_dpif_recirc_get_ofproto(const struct dpif_backer *backer, - uint32_t recirc_id) -{ - struct dpif_backer_recirc_node *node; - - node = CONTAINER_OF(cmap_find(&backer->recirc_map, recirc_id), - struct dpif_backer_recirc_node, cmap_node); - - return node ? node->ofproto : NULL; -} - -uint32_t -ofproto_dpif_alloc_recirc_id(struct ofproto_dpif *ofproto) -{ - struct dpif_backer *backer = ofproto->backer; - uint32_t recirc_id = recirc_id_alloc(backer->rid_pool); - - if (recirc_id) { - struct dpif_backer_recirc_node *node = xmalloc(sizeof *node); - - node->recirc_id = recirc_id; - node->ofproto = ofproto; - - ovs_mutex_lock(&backer->recirc_mutex); - cmap_insert(&backer->recirc_map, &node->cmap_node, node->recirc_id); - ovs_mutex_unlock(&backer->recirc_mutex); - } - - return recirc_id; -} - -void -ofproto_dpif_free_recirc_id(struct ofproto_dpif *ofproto, uint32_t recirc_id) -{ - struct dpif_backer *backer = ofproto->backer; - struct dpif_backer_recirc_node *node; - - node = CONTAINER_OF(cmap_find(&backer->recirc_map, recirc_id), - struct dpif_backer_recirc_node, cmap_node); - if (node) { - ovs_mutex_lock(&backer->recirc_mutex); - cmap_remove(&backer->recirc_map, &node->cmap_node, node->recirc_id); - ovs_mutex_unlock(&backer->recirc_mutex); - recirc_id_free(backer->rid_pool, node->recirc_id); - - /* 'recirc_id' should never be freed by non-owning 'ofproto'. */ - ovs_assert(node->ofproto == ofproto); - - /* RCU postpone the free, since other threads may be referring - * to 'node' at same time. */ - ovsrcu_postpone(free, node); - } -} - int ofproto_dpif_add_internal_flow(struct ofproto_dpif *ofproto, const struct match *match, int priority, diff --git a/ofproto/ofproto-dpif.h b/ofproto/ofproto-dpif.h index 19c91f0a0..956692422 100644 --- a/ofproto/ofproto-dpif.h +++ b/ofproto/ofproto-dpif.h @@ -77,11 +77,6 @@ size_t ofproto_dpif_get_max_mpls_depth(const struct ofproto_dpif *); bool ofproto_dpif_get_enable_recirc(const struct ofproto_dpif *); bool ofproto_dpif_get_enable_ufid(struct dpif_backer *backer); -struct rule_dpif *rule_dpif_lookup(struct ofproto_dpif *, struct flow *, - struct flow_wildcards *, bool take_ref, - const struct dpif_flow_stats *, - uint8_t *table_id); - struct rule_dpif *rule_dpif_lookup_from_table(struct ofproto_dpif *, struct flow *, struct flow_wildcards *, @@ -92,14 +87,6 @@ struct rule_dpif *rule_dpif_lookup_from_table(struct ofproto_dpif *, bool may_packet_in, bool honor_table_miss); -/* If 'recirc_id' is set, starts looking up from internal table for - * post recirculation flows or packets. Otherwise, starts from table 0. */ -static inline uint8_t -rule_dpif_lookup_get_init_table_id(const struct flow *flow) -{ - return flow->recirc_id ? TBL_INTERNAL : 0; -} - static inline void rule_dpif_ref(struct rule_dpif *); static inline void rule_dpif_unref(struct rule_dpif *); @@ -115,7 +102,6 @@ uint8_t rule_dpif_get_table(const struct rule_dpif *); bool table_is_internal(uint8_t table_id); const struct rule_actions *rule_dpif_get_actions(const struct rule_dpif *); -uint32_t rule_dpif_get_recirc_id(struct rule_dpif *); void rule_set_recirc_id(struct rule *, uint32_t id); ovs_be64 rule_dpif_get_flow_cookie(const struct rule_dpif *rule); @@ -159,83 +145,9 @@ void ofproto_dpif_flow_mod(struct ofproto_dpif *, struct ofputil_flow_mod *); struct rule_dpif *ofproto_dpif_refresh_rule(struct rule_dpif *); struct ofport_dpif *odp_port_to_ofport(const struct dpif_backer *, odp_port_t); +struct ofport_dpif *ofp_port_to_ofport(const struct ofproto_dpif *, + ofp_port_t); -/* - * Recirculation - * ============= - * - * Recirculation is a technique to allow a frame to re-enter the packet - * processing path for one or multiple times to achieve more flexible packet - * processing in the data path. MPLS handling and selecting bond slave port - * of a bond ports. - * - * Data path and user space interface - * ----------------------------------- - * - * Two new fields, recirc_id and dp_hash, are added to the current flow data - * structure. They are both of type uint32_t. In addition, a new action, - * RECIRC, are added. - * - * The value recirc_id is used to distinguish a packet from multiple - * iterations of recirculation. A packet initially received is considered of - * having recirc_id of 0. Recirc_id is managed by the user space, opaque to - * the data path. - * - * On the other hand, dp_hash can only be computed by the data path, opaque to - * the user space. In fact, user space may not able to recompute the hash - * value. The dp_hash value should be wildcarded when for a newly received - * packet. RECIRC action specifies whether the hash is computed. If computed, - * how many fields to be included in the hash computation. The computed hash - * value is stored into the dp_hash field prior to recirculation. - * - * The RECIRC action computes and set the dp_hash field, set the recirc_id - * field and then reprocess the packet as if it was received on the same input - * port. RECIRC action works like a function call; actions listed behind the - * RECIRC action will be executed after its execution. RECIRC action can be - * nested, data path implementation limits the number of recirculation executed - * to prevent unreasonable nesting depth or infinite loop. - * - * Both flow fields and the RECIRC action are exposed as OpenFlow fields via - * Nicira extensions. - * - * Post recirculation flow - * ------------------------ - * - * At the OpenFlow level, post recirculation rules are always hidden from the - * controller. They are installed in table 254 which is set up as a hidden - * table during boot time. Those rules are managed by the local user space - * program only. - * - * To speed up the classifier look up process, recirc_id is always reflected - * into the metadata field, since recirc_id is required to be exactly matched. - * - * Classifier look up always starts with table 254. A post recirculation flow - * lookup should find its hidden rule within this table. On the other hand, A - * newly received packet should miss all post recirculation rules because its - * recirc_id is zero, then hit a pre-installed lower priority rule to redirect - * classifier to look up starting from table 0: - * - * * , actions=resubmit(,0) - * - * Post recirculation data path flows are managed like other data path flows. - * They are created on demand. Miss handling, stats collection and revalidation - * work the same way as regular flows. - * - * If the bridge which originates the recirculation is different from the bridge - * that receives the post recirculation packet (e.g. when patch port is used), - * the packet will be processed directly by the recirculation bridge with - * in_port set to OFPP_NONE. Admittedly, doing this limits the recirculation - * bridge from matching on in_port of post recirculation packets, and will be - * fixed in the near future. - * - * TODO: Always restore the correct in_port. - * - */ - -struct ofproto_dpif *ofproto_dpif_recirc_get_ofproto(const struct dpif_backer *ofproto, - uint32_t recirc_id); -uint32_t ofproto_dpif_alloc_recirc_id(struct ofproto_dpif *ofproto); -void ofproto_dpif_free_recirc_id(struct ofproto_dpif *ofproto, uint32_t recirc_id); int ofproto_dpif_add_internal_flow(struct ofproto_dpif *, const struct match *, int priority, uint16_t idle_timeout, diff --git a/tests/mpls-xlate.at b/tests/mpls-xlate.at index e2ef2e7c6..571b8ce45 100644 --- a/tests/mpls-xlate.at +++ b/tests/mpls-xlate.at @@ -31,8 +31,12 @@ dnl Setup multiple MPLS tags. AT_CHECK([ovs-ofctl del-flows br0]) AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br0 in_port=local,dl_type=0x0800,action=push_mpls:0x8847,set_field:10-\>mpls_label,push_mpls:0x8847,set_field:20-\>mpls_label,output:1]) -AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br0 table=0,dl_type=0x8847,in_port=1,mpls_label=60,action=pop_mpls:0x8847,goto_table:1]) -AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br0 table=1,dl_type=0x8847,in_port=1,mpls_label=50,action=pop_mpls:0x0800,output:LOCAL]) +# The resubmits will be executed after recirculation, which preserves the +# register values. +AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br0 cookie=0xa,table=0,dl_type=0x8847,in_port=1,mpls_label=60,action=set_field:10-\>reg0,pop_mpls:0x8847,goto_table:1]) +# The pop_mpls below recirculates from within a resubmit +# After recirculation the (restored) register value is moved to IP ttl. +AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br0 cookie=0xb,table=1,dl_type=0x8847,in_port=1,mpls_label=50,action=push:NXM_NX_REG0[[0..7]],pop_mpls:0x0800,set_field:0-\>nw_ttl,pop:NXM_NX_REG1[[0..7]],move:NXM_NX_REG1[[0..7]]-\>NXM_NX_IP_TTL[[]],output:LOCAL]) dnl Double MPLS push AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(100),eth(src=f8:bc:12:44:34:b6,dst=f8:bc:12:46:58:e0),eth_type(0x0800),ipv4(src=1.1.2.92,dst=1.1.2.88,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout]) @@ -41,9 +45,19 @@ AT_CHECK([tail -1 stdout], [0], ]) dnl Double MPLS pop -AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=f8:bc:12:44:34:b6,dst=f8:bc:12:46:58:e0),eth_type(0x8847),mpls(label=60,tc=0/0,ttl=64,bos=0)'], [0], [stdout]) +AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=f8:bc:12:44:34:b6,dst=f8:bc:12:46:58:e0),eth_type(0x8847),mpls(label=60,tc=0/0,ttl=64,bos=0)' -generate], [0], [stdout]) AT_CHECK([tail -1 stdout], [0], - [Datapath actions: pop_mpls(eth_type=0x8847),recirc(300) + [Datapath actions: pop_mpls(eth_type=0x8847),recirc(1) +]) + +AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'recirc_id(1),in_port(1),eth(src=f8:bc:12:44:34:b6,dst=f8:bc:12:46:58:e0),eth_type(0x8847),mpls(label=50,tc=0/0,ttl=64,bos=0)' -generate], [0], [stdout]) +AT_CHECK([tail -1 stdout], [0], + [Datapath actions: pop_mpls(eth_type=0x800),recirc(2) +]) + +AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'recirc_id(2),in_port(1),eth(src=f8:bc:12:44:34:b6,dst=f8:bc:12:46:58:e0),eth_type(0x0800),ipv4(src=1.1.2.92,dst=1.1.2.88,proto=47,tos=0,ttl=64,frag=no)' -generate], [0], [stdout]) +AT_CHECK([tail -1 stdout], [0], + [Datapath actions: set(ipv4(ttl=10)),100 ]) OVS_VSWITCHD_STOP diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at index b4d7a23da..f3d886f1a 100644 --- a/tests/ofproto-dpif.at +++ b/tests/ofproto-dpif.at @@ -186,7 +186,7 @@ table=0 priority=2 in_port=5 dl_vlan=1 actions=drop AT_CHECK([ovs-ofctl add-flows br-int flows.txt]) # Sends a packet to trigger recirculation. -# Should generate recirc_id(0x12d),dp_hash(0xc1261ba2/0xff). +# Should generate recirc_id(0x2),dp_hash(0xc1261ba2/0xff). AT_CHECK([ovs-appctl netdev-dummy/receive p5 "in_port(5),eth(src=50:54:00:00:00:05,dst=50:54:00:00:01:00),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1)"]) # Collects flow stats. @@ -195,7 +195,7 @@ AT_CHECK([ovs-appctl revalidator/purge], [0]) # Checks the flow stats in br1, should only be one flow with non-zero # 'n_packets' from internal table. AT_CHECK([ovs-appctl bridge/dump-flows br1 | ofctl_strip | grep -- "n_packets" | grep -- "table_id" | sed -e 's/dp_hash=0x[[0-9a-f]][[0-9a-f]]*/dp_hash=0x0/' -e 's/output:[[0-9]][[0-9]]*/output/'], [0], [dnl -table_id=254, n_packets=1, n_bytes=64, priority=20,recirc_id=0x12d,dp_hash=0x0/0xff,actions=output +table_id=254, n_packets=1, n_bytes=64, priority=20,recirc_id=0x2,dp_hash=0x0/0xff,actions=output ]) # Checks the flow stats in br-int, should be only one match. @@ -1571,7 +1571,8 @@ cookie=0xd dl_src=60:66:66:66:00:07 actions=pop_mpls:0x0800,learn(table=1,hard_t cookie=0xd dl_src=60:66:66:66:00:08 actions=pop_mpls:0x0806,resubmit(1,1) cookie=0xd table=1 arp actions=controller -cookie=0xd dl_src=60:66:66:66:00:09 actions=pop_mpls:0x0800,mod_nw_tos:48,controller +cookie=0xdeadbeef table=2 dl_src=60:66:66:66:00:09 actions=pop_mpls:0x0800,mod_nw_tos:48 +cookie=0xd dl_src=60:66:66:66:00:09 actions=resubmit(,2),controller cookie=0xd dl_src=60:66:66:66:00:0a actions=pop_mpls:0x0800,mod_nw_dst:10.0.0.1,controller cookie=0xd dl_src=60:66:66:66:00:0b actions=pop_mpls:0x0800,mod_nw_src:10.0.0.1,controller @@ -1580,20 +1581,20 @@ cookie=0xd dl_src=60:66:66:66:01:01 actions=pop_mpls:0x8847,dec_mpls_ttl,control cookie=0xd dl_src=60:66:66:66:01:02 actions=pop_mpls:0x8848,load:3->OXM_OF_MPLS_TC[[]],controller cookie=0xd dl_src=60:66:66:66:02:00 actions=pop_mpls:0x8847,pop_mpls:0x0800,controller -cookie=0xd dl_src=60:66:66:66:02:01 actions=pop_mpls:0x8848,pop_mpls:0x0800,dec_ttl,controller -cookie=0xd dl_src=60:66:66:66:02:10 actions=pop_mpls:0x8847,dec_mpls_ttl,pop_mpls:0x0800,dec_ttl,controller +cookie=0xe dl_src=60:66:66:66:02:01 actions=pop_mpls:0x8848,pop_mpls:0x0800,dec_ttl,controller +cookie=0xe dl_src=60:66:66:66:02:10 actions=pop_mpls:0x8847,dec_mpls_ttl,pop_mpls:0x0800,dec_ttl,controller -cookie=0xd dl_src=60:66:66:66:03:00 actions=pop_mpls:0x8848,pop_mpls:0x8848,controller -cookie=0xd dl_src=60:66:66:66:03:01 actions=pop_mpls:0x8847,pop_mpls:0x8847,dec_mpls_ttl,controller -cookie=0xd dl_src=60:66:66:66:03:10 actions=pop_mpls:0x8848,dec_mpls_ttl,pop_mpls:0x8848,dec_mpls_ttl,controller +cookie=0xe dl_src=60:66:66:66:03:00 actions=pop_mpls:0x8848,pop_mpls:0x8848,controller +cookie=0xe dl_src=60:66:66:66:03:01 actions=pop_mpls:0x8847,pop_mpls:0x8847,dec_mpls_ttl,controller +cookie=0xe dl_src=60:66:66:66:03:10 actions=pop_mpls:0x8848,dec_mpls_ttl,pop_mpls:0x8848,dec_mpls_ttl,controller -cookie=0xd dl_src=60:66:66:66:04:00 actions=pop_mpls:0x0800,push_mpls:0x8847,controller -cookie=0xd dl_src=60:66:66:66:04:01 actions=pop_mpls:0x0800,push_mpls:0x8848,dec_mpls_ttl,controller -cookie=0xd dl_src=60:66:66:66:04:10 actions=pop_mpls:0x0800,dec_ttl,push_mpls:0x8848,dec_mpls_ttl,controller +cookie=0xf dl_src=60:66:66:66:04:00 actions=pop_mpls:0x0800,push_mpls:0x8847,controller +cookie=0xf dl_src=60:66:66:66:04:01 actions=pop_mpls:0x0800,push_mpls:0x8848,dec_mpls_ttl,controller +cookie=0xf dl_src=60:66:66:66:04:10 actions=pop_mpls:0x0800,dec_ttl,push_mpls:0x8848,dec_mpls_ttl,controller -cookie=0xd dl_src=60:66:66:66:05:00 actions=push_mpls:0x8848,pop_mpls:0x8847,controller -cookie=0xd dl_src=60:66:66:66:05:01 actions=push_mpls:0x8847,pop_mpls:0x8848,dec_mpls_ttl,controller -cookie=0xd dl_src=60:66:66:66:05:10 actions=push_mpls:0x8848,dec_mpls_ttl,pop_mpls:0x8847,dec_mpls_ttl,controller +cookie=0x5 dl_src=60:66:66:66:05:00 actions=push_mpls:0x8848,pop_mpls:0x8847,controller +cookie=0x5 dl_src=60:66:66:66:05:01 actions=push_mpls:0x8847,pop_mpls:0x8848,dec_mpls_ttl,controller +cookie=0x5 dl_src=60:66:66:66:05:10 actions=push_mpls:0x8848,dec_mpls_ttl,pop_mpls:0x8847,dec_mpls_ttl,controller ]) AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) @@ -1867,13 +1868,13 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6]) OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:01,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:01,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:01,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 ]) @@ -1893,13 +1894,13 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6]) OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:02,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=10.0.0.1,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2dee dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:02,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=10.0.0.1,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2dee dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:02,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=10.0.0.1,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2dee ]) @@ -1919,13 +1920,13 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6]) OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:03,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.2,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7743 dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:03,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.2,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7743 dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:03,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.2,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7743 ]) @@ -1945,13 +1946,13 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6]) OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:04,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.2,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7743 dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:04,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.2,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7743 dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:04,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.2,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7743 ]) @@ -1971,13 +1972,13 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6]) OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.106,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:76db dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.106,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:76db dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.106,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:76db ]) @@ -1997,13 +1998,13 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6]) OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:06,dl_dst=50:54:00:00:00:07,nw_src=192.168.255.255,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7745 dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:06,dl_dst=50:54:00:00:00:07,nw_src=192.168.255.255,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7745 dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:06,dl_dst=50:54:00:00:00:07,nw_src=192.168.255.255,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7745 ]) @@ -2023,13 +2024,13 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6]) OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:07,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:07,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:07,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 ]) @@ -2073,13 +2074,13 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6]) OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:09,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=48,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:09,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=48,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:09,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=48,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 ]) @@ -2099,13 +2100,13 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6]) OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:0a,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=10.0.0.1,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2dee dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:0a,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=10.0.0.1,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2dee dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:0a,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=10.0.0.1,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2dee ]) @@ -2125,13 +2126,13 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6]) OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:0b,dl_dst=50:54:00:00:00:07,nw_src=10.0.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2ded dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:0b,dl_dst=50:54:00:00:00:07,nw_src=10.0.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2ded dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:0b,dl_dst=50:54:00:00:00:07,nw_src=10.0.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2ded ]) @@ -2179,13 +2180,13 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6]) OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log], [0], [dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=62 in_port=1 (via action) data_len=62 (unbuffered) mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:01:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=30,mpls_bos=1 dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=62 in_port=1 (via action) data_len=62 (unbuffered) mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:01:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=30,mpls_bos=1 dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=62 in_port=1 (via action) data_len=62 (unbuffered) mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:01:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=30,mpls_bos=1 ]) @@ -2233,13 +2234,13 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6]) OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log], [0], [dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:02:00,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:02:00,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:02:00,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 ]) @@ -2256,17 +2257,18 @@ AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor for i in 1 2 3; do ovs-appctl netdev-dummy/receive p1 '50 54 00 00 00 07 60 66 66 66 02 01 88 48 00 01 40 20 00 01 41 1f 45 00 00 2c 00 00 00 00 ff 06 3b 78 c0 a8 00 01 c0 a8 00 02 00 50 00 00 00 00 00 2a 00 00 00 2a 50 00 27 10 77 44 00 00 48 4f 47 45' done + OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6]) OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=58 in_port=1 (via action) data_len=58 (unbuffered) tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:02:01,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=58 in_port=1 (via action) data_len=58 (unbuffered) tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:02:01,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=58 in_port=1 (via action) data_len=58 (unbuffered) tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:02:01,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 ]) @@ -2274,7 +2276,7 @@ AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore]) dnl Modified MPLS pop action. dnl The input is a frame with two MPLS label stack entries which tcpdump -vve shows as: -dnl 60:66:66:66:02:10 > 50:54:00:00:02:10, ethertype MPLS unicast (0x8847), length 66: MPLS (label 20, exp 0, ttl 32) +dnl 60:66:66:66:02:10 > 50:54:00:00:00:07, ethertype MPLS unicast (0x8847), length 66: MPLS (label 20, exp 0, ttl 32) dnl (label 20, exp 0, [S], ttl 31) dnl (tos 0x0, ttl 254, id 0, offset 0, flags [none], proto TCP (6), length 44) dnl 192.168.0.1.80 > 192.168.0.2.0: Flags [none], cksum 0x7744 (correct), seq 42:46, win 10000, length 4 @@ -2287,13 +2289,13 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6]) OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=58 in_port=1 (via action) data_len=58 (unbuffered) tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:02:10,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=58 in_port=1 (via action) data_len=58 (unbuffered) tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:02:10,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=58 in_port=1 (via action) data_len=58 (unbuffered) tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:02:10,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 ]) @@ -2301,7 +2303,7 @@ AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore]) dnl Modified MPLS pop action. dnl The input is a frame with three MPLS label stack entries which tcpdump -vve shows as: -dnl 60:66:66:66:03:00 > 50:54:00:00:00:00, ethertype MPLS unicast (0x8847), length 66: MPLS (label 20, exp 0, ttl 32) +dnl 60:66:66:66:03:00 > 50:54:00:00:00:07, ethertype MPLS unicast (0x8847), length 66: MPLS (label 20, exp 0, ttl 32) dnl (label 20, exp 0, ttl 31) dnl (label 20, exp 0, [S], ttl 30) dnl (tos 0x0, ttl 254, id 0, offset 0, flags [none], proto TCP (6), length 44) @@ -2315,13 +2317,13 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6]) OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log], [0], [dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=62 in_port=1 (via action) data_len=62 (unbuffered) mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:03:00,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=30,mpls_bos=1 dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=62 in_port=1 (via action) data_len=62 (unbuffered) mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:03:00,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=30,mpls_bos=1 dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=62 in_port=1 (via action) data_len=62 (unbuffered) mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:03:00,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=30,mpls_bos=1 ]) @@ -2343,13 +2345,13 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6]) OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log], [0], [dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=62 in_port=1 (via action) data_len=62 (unbuffered) mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:03:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=29,mpls_bos=1 dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=62 in_port=1 (via action) data_len=62 (unbuffered) mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:03:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=29,mpls_bos=1 dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=62 in_port=1 (via action) data_len=62 (unbuffered) mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:03:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=29,mpls_bos=1 ]) @@ -2371,13 +2373,13 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6]) OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log], [0], [dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=62 in_port=1 (via action) data_len=62 (unbuffered) mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:03:10,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=29,mpls_bos=1 dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=62 in_port=1 (via action) data_len=62 (unbuffered) mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:03:10,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=29,mpls_bos=1 dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=62 in_port=1 (via action) data_len=62 (unbuffered) mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:03:10,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=29,mpls_bos=1 ]) @@ -2397,13 +2399,13 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6]) OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xf total_len=62 in_port=1 (via action) data_len=62 (unbuffered) mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:04:00,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=255,mpls_bos=1 dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xf total_len=62 in_port=1 (via action) data_len=62 (unbuffered) mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:04:00,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=255,mpls_bos=1 dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xf total_len=62 in_port=1 (via action) data_len=62 (unbuffered) mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:04:00,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=255,mpls_bos=1 ]) @@ -2423,13 +2425,13 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6]) OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xf total_len=62 in_port=1 (via action) data_len=62 (unbuffered) mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:04:01,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=254,mpls_bos=1 dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xf total_len=62 in_port=1 (via action) data_len=62 (unbuffered) mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:04:01,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=254,mpls_bos=1 dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xf total_len=62 in_port=1 (via action) data_len=62 (unbuffered) mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:04:01,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=254,mpls_bos=1 ]) @@ -2449,13 +2451,13 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6]) OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xf total_len=62 in_port=1 (via action) data_len=62 (unbuffered) mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:04:10,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=253,mpls_bos=1 dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xf total_len=62 in_port=1 (via action) data_len=62 (unbuffered) mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:04:10,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=253,mpls_bos=1 dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0xf total_len=62 in_port=1 (via action) data_len=62 (unbuffered) mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:04:10,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=253,mpls_bos=1 ]) @@ -2471,17 +2473,18 @@ AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor for i in 1 2 3; do ovs-appctl netdev-dummy/receive p1 '50 54 00 00 00 07 60 66 66 66 05 00 88 47 00 01 41 20 45 00 00 2c 00 00 00 00 ff 06 3a 78 c0 a8 00 01 c0 a8 00 02 00 50 00 00 00 00 00 2a 00 00 00 2a 50 00 27 10 77 44 00 00 48 4f 47 45' done + OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6]) OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log], [0], [dnl -NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=62 in_port=1 (via action) data_len=62 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0x5 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:05:00,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=32,mpls_bos=1 dnl -NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=62 in_port=1 (via action) data_len=62 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0x5 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:05:00,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=32,mpls_bos=1 dnl -NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=62 in_port=1 (via action) data_len=62 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0x5 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:05:00,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=32,mpls_bos=1 ]) @@ -2501,13 +2504,13 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6]) OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log], [0], [dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0x5 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:05:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=31,mpls_bos=1 dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0x5 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:05:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=31,mpls_bos=1 dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0x5 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:05:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=31,mpls_bos=1 ]) @@ -2523,22 +2526,26 @@ AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor for i in 1 2 3; do ovs-appctl netdev-dummy/receive p1 '50 54 00 00 00 07 60 66 66 66 05 10 88 47 00 01 41 20 45 00 00 2c 00 00 00 00 ff 06 3a 78 c0 a8 00 01 c0 a8 00 02 00 50 00 00 00 00 00 2a 00 00 00 2a 50 00 27 10 77 44 00 00 48 4f 47 45' done + OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6]) OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log], [0], [dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0x5 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:05:10,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=31,mpls_bos=1 dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0x5 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:05:10,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=31,mpls_bos=1 dnl -NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) +NXT_PACKET_IN (xid=0x0): cookie=0x5 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:05:10,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=31,mpls_bos=1 ]) AT_CHECK([ovs-appctl revalidator/purge], [0]) AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl + cookie=0x5, n_packets=3, n_bytes=186, dl_src=60:66:66:66:05:00 actions=push_mpls:0x8848,pop_mpls:0x8847,CONTROLLER:65535 + cookie=0x5, n_packets=3, n_bytes=186, dl_src=60:66:66:66:05:01 actions=push_mpls:0x8847,pop_mpls:0x8848,dec_mpls_ttl,CONTROLLER:65535 + cookie=0x5, n_packets=3, n_bytes=186, dl_src=60:66:66:66:05:10 actions=push_mpls:0x8848,dec_mpls_ttl,pop_mpls:0x8847,dec_mpls_ttl,CONTROLLER:65535 cookie=0xa, n_packets=3, n_bytes=180, dl_src=40:44:44:44:44:42 actions=push_mpls:0x8847,load:0xa->OXM_OF_MPLS_LABEL[[]],load:0x3->OXM_OF_MPLS_TC[[]],CONTROLLER:65535 cookie=0xa, n_packets=3, n_bytes=180, dl_src=40:44:44:44:44:43 actions=push_mpls:0x8847,load:0xa->OXM_OF_MPLS_LABEL[[]],load:0x3->OXM_OF_MPLS_TC[[]],CONTROLLER:65535 cookie=0xa, n_packets=3, n_bytes=180, dl_src=40:44:44:44:44:44 actions=push_mpls:0x8847,load:0xa->OXM_OF_MPLS_LABEL[[]],load:0x3->OXM_OF_MPLS_TC[[]],CONTROLLER:65535 @@ -2558,26 +2565,24 @@ AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl cookie=0xd, n_packets=3, n_bytes=186, dl_src=60:66:66:66:00:05 actions=pop_mpls:0x0800,multipath(eth_src,50,modulo_n,256,0,NXM_OF_IP_SRC[[0..7]]),CONTROLLER:65535 cookie=0xd, n_packets=3, n_bytes=186, dl_src=60:66:66:66:00:06 actions=pop_mpls:0x0800,bundle_load(eth_src,50,hrw,ofport,NXM_OF_IP_SRC[[0..15]],slaves:1,2),CONTROLLER:65535 cookie=0xd, n_packets=3, n_bytes=186, dl_src=60:66:66:66:00:07 actions=pop_mpls:0x0800,learn(table=1,hard_timeout=60,eth_type=0x800,nw_proto=6,NXM_OF_IP_SRC[[]]=NXM_OF_IP_DST[[]]),CONTROLLER:65535 - cookie=0xd, n_packets=3, n_bytes=186, dl_src=60:66:66:66:00:09 actions=pop_mpls:0x0800,mod_nw_tos:48,CONTROLLER:65535 + cookie=0xd, n_packets=3, n_bytes=186, dl_src=60:66:66:66:00:09 actions=resubmit(,2),CONTROLLER:65535 cookie=0xd, n_packets=3, n_bytes=186, dl_src=60:66:66:66:00:0a actions=pop_mpls:0x0800,mod_nw_dst:10.0.0.1,CONTROLLER:65535 cookie=0xd, n_packets=3, n_bytes=186, dl_src=60:66:66:66:00:0b actions=pop_mpls:0x0800,mod_nw_src:10.0.0.1,CONTROLLER:65535 - cookie=0xd, n_packets=3, n_bytes=186, dl_src=60:66:66:66:04:00 actions=pop_mpls:0x0800,push_mpls:0x8847,CONTROLLER:65535 - cookie=0xd, n_packets=3, n_bytes=186, dl_src=60:66:66:66:04:01 actions=pop_mpls:0x0800,push_mpls:0x8848,dec_mpls_ttl,CONTROLLER:65535 - cookie=0xd, n_packets=3, n_bytes=186, dl_src=60:66:66:66:04:10 actions=pop_mpls:0x0800,dec_ttl,push_mpls:0x8848,dec_mpls_ttl,CONTROLLER:65535 - cookie=0xd, n_packets=3, n_bytes=186, dl_src=60:66:66:66:05:00 actions=push_mpls:0x8848,pop_mpls:0x8847,CONTROLLER:65535 - cookie=0xd, n_packets=3, n_bytes=186, dl_src=60:66:66:66:05:01 actions=push_mpls:0x8847,pop_mpls:0x8848,dec_mpls_ttl,CONTROLLER:65535 - cookie=0xd, n_packets=3, n_bytes=186, dl_src=60:66:66:66:05:10 actions=push_mpls:0x8848,dec_mpls_ttl,pop_mpls:0x8847,dec_mpls_ttl,CONTROLLER:65535 cookie=0xd, n_packets=3, n_bytes=186, dl_src=60:66:66:66:66:66 actions=pop_mpls:0x0800,CONTROLLER:65535 cookie=0xd, n_packets=3, n_bytes=198, dl_src=60:66:66:66:01:00 actions=pop_mpls:0x8848,CONTROLLER:65535 cookie=0xd, n_packets=3, n_bytes=198, dl_src=60:66:66:66:01:01 actions=pop_mpls:0x8847,dec_mpls_ttl,CONTROLLER:65535 cookie=0xd, n_packets=3, n_bytes=198, dl_src=60:66:66:66:01:02 actions=pop_mpls:0x8848,load:0x3->OXM_OF_MPLS_TC[[]],CONTROLLER:65535 cookie=0xd, n_packets=3, n_bytes=198, dl_src=60:66:66:66:02:00 actions=pop_mpls:0x8847,pop_mpls:0x0800,CONTROLLER:65535 - cookie=0xd, n_packets=3, n_bytes=198, dl_src=60:66:66:66:02:01 actions=pop_mpls:0x8848,pop_mpls:0x0800,dec_ttl,CONTROLLER:65535 - cookie=0xd, n_packets=3, n_bytes=198, dl_src=60:66:66:66:02:10 actions=pop_mpls:0x8847,dec_mpls_ttl,pop_mpls:0x0800,dec_ttl,CONTROLLER:65535 - cookie=0xd, n_packets=3, n_bytes=210, dl_src=60:66:66:66:03:00 actions=pop_mpls:0x8848,pop_mpls:0x8848,CONTROLLER:65535 - cookie=0xd, n_packets=3, n_bytes=210, dl_src=60:66:66:66:03:01 actions=pop_mpls:0x8847,pop_mpls:0x8847,dec_mpls_ttl,CONTROLLER:65535 - cookie=0xd, n_packets=3, n_bytes=210, dl_src=60:66:66:66:03:10 actions=pop_mpls:0x8848,dec_mpls_ttl,pop_mpls:0x8848,dec_mpls_ttl,CONTROLLER:65535 cookie=0xd, table=1, n_packets=3, n_bytes=168, arp actions=CONTROLLER:65535 + cookie=0xdeadbeef, table=2, n_packets=3, n_bytes=186, dl_src=60:66:66:66:00:09 actions=pop_mpls:0x0800,mod_nw_tos:48 + cookie=0xe, n_packets=3, n_bytes=198, dl_src=60:66:66:66:02:01 actions=pop_mpls:0x8848,pop_mpls:0x0800,dec_ttl,CONTROLLER:65535 + cookie=0xe, n_packets=3, n_bytes=198, dl_src=60:66:66:66:02:10 actions=pop_mpls:0x8847,dec_mpls_ttl,pop_mpls:0x0800,dec_ttl,CONTROLLER:65535 + cookie=0xe, n_packets=3, n_bytes=210, dl_src=60:66:66:66:03:00 actions=pop_mpls:0x8848,pop_mpls:0x8848,CONTROLLER:65535 + cookie=0xe, n_packets=3, n_bytes=210, dl_src=60:66:66:66:03:01 actions=pop_mpls:0x8847,pop_mpls:0x8847,dec_mpls_ttl,CONTROLLER:65535 + cookie=0xe, n_packets=3, n_bytes=210, dl_src=60:66:66:66:03:10 actions=pop_mpls:0x8848,dec_mpls_ttl,pop_mpls:0x8848,dec_mpls_ttl,CONTROLLER:65535 + cookie=0xf, n_packets=3, n_bytes=186, dl_src=60:66:66:66:04:00 actions=pop_mpls:0x0800,push_mpls:0x8847,CONTROLLER:65535 + cookie=0xf, n_packets=3, n_bytes=186, dl_src=60:66:66:66:04:01 actions=pop_mpls:0x0800,push_mpls:0x8848,dec_mpls_ttl,CONTROLLER:65535 + cookie=0xf, n_packets=3, n_bytes=186, dl_src=60:66:66:66:04:10 actions=pop_mpls:0x0800,dec_ttl,push_mpls:0x8848,dec_mpls_ttl,CONTROLLER:65535 NXST_FLOW reply: ]) @@ -2661,13 +2666,13 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6]) OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl -OFPT_PACKET_IN (OF1.2) (xid=0x0): table_id=254 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) +OFPT_PACKET_IN (OF1.2) (xid=0x0): total_len=58 in_port=1 (via action) data_len=58 (unbuffered) tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:08,dl_dst=50:54:00:00:00:01,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=32,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 dnl -OFPT_PACKET_IN (OF1.2) (xid=0x0): table_id=254 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) +OFPT_PACKET_IN (OF1.2) (xid=0x0): total_len=58 in_port=1 (via action) data_len=58 (unbuffered) tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:08,dl_dst=50:54:00:00:00:01,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=32,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 dnl -OFPT_PACKET_IN (OF1.2) (xid=0x0): table_id=254 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) +OFPT_PACKET_IN (OF1.2) (xid=0x0): total_len=58 in_port=1 (via action) data_len=58 (unbuffered) tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:08,dl_dst=50:54:00:00:00:01,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=32,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 ]) -- cgit v1.2.1 From 1d741d6dfce5752b8a04568e18da15a2788b70b0 Mon Sep 17 00:00:00 2001 From: Jarno Rajahalme Date: Thu, 26 Mar 2015 11:18:17 -0700 Subject: ofproto-dpif-xlate: Fix MPLS recirculation. Prior to this patch MPLS recirculation was not performed on a table lookup following an MPLS_POP action. This patch refactors MPLS recirculation triggering so that a table action can be re-done after recirculation if that table action follows an MPLS_POP action. Recirculation for a patch port traversal (which also does a table lookup) after an MPLS_POP action does not need to store the output action, as recirculation without any post-recirculation actions causes the table lookup to happen anyway. Furthermore, the stack actions now have the same post-MPLS_POP optimization as the SET_FIELD and MOVE actions had already: recirculation is triggered only if the register in the action is L3 or higher. Signed-off-by: Jarno Rajahalme Acked-by: Ben Pfaff --- ofproto/ofproto-dpif-xlate.c | 165 ++++++++++++++++++++----------------------- 1 file changed, 76 insertions(+), 89 deletions(-) diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index 3e22a5fa0..4f82238be 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -293,10 +293,7 @@ struct xlate_ctx { /* True if a packet was but is no longer MPLS (due to an MPLS pop action). * This is a trigger for recirculation in cases where translating an action * or looking up a flow requires access to the fields of the packet after - * the MPLS label stack that was originally present. - * - * XXX: output to a table and patch port do not currently recirculate even - * if this is true. */ + * the MPLS label stack that was originally present. */ bool was_mpls; /* OpenFlow 1.1+ action set. @@ -312,6 +309,19 @@ struct xlate_ctx { static void xlate_action_set(struct xlate_ctx *ctx); +static void +ctx_trigger_recirculation(struct xlate_ctx *ctx) +{ + ctx->exit = true; + ctx->recirc_action_offset = ctx->action_set.size; +} + +static bool +ctx_first_recirculation_action(const struct xlate_ctx *ctx) +{ + return ctx->recirc_action_offset == ctx->action_set.size; +} + static inline bool exit_recirculates(const struct xlate_ctx *ctx) { @@ -3059,6 +3069,11 @@ static void xlate_table_action(struct xlate_ctx *ctx, ofp_port_t in_port, uint8_t table_id, bool may_packet_in, bool honor_table_miss) { + /* Check if we need to recirculate before matching in a table. */ + if (ctx->was_mpls) { + ctx_trigger_recirculation(ctx); + return; + } if (xlate_resubmit_resource_check(ctx)) { struct flow_wildcards *wc; uint8_t old_table_id = ctx->table_id; @@ -3961,85 +3976,6 @@ xlate_action_set(struct xlate_ctx *ctx) ofpbuf_uninit(&action_list); } -static bool -ofpact_needs_recirculation_after_mpls(const struct ofpact *a, struct xlate_ctx *ctx) -{ - struct flow_wildcards *wc = &ctx->xout->wc; - struct flow *flow = &ctx->xin->flow; - - if (!ctx->was_mpls) { - return false; - } - - switch (a->type) { - case OFPACT_OUTPUT: - case OFPACT_GROUP: - case OFPACT_CONTROLLER: - case OFPACT_STRIP_VLAN: - case OFPACT_SET_VLAN_PCP: - case OFPACT_SET_VLAN_VID: - case OFPACT_ENQUEUE: - case OFPACT_PUSH_VLAN: - case OFPACT_SET_ETH_SRC: - case OFPACT_SET_ETH_DST: - case OFPACT_SET_TUNNEL: - case OFPACT_SET_QUEUE: - case OFPACT_POP_QUEUE: - case OFPACT_CONJUNCTION: - case OFPACT_NOTE: - case OFPACT_UNROLL_XLATE: - case OFPACT_OUTPUT_REG: - case OFPACT_EXIT: - case OFPACT_METER: - case OFPACT_WRITE_METADATA: - case OFPACT_WRITE_ACTIONS: - case OFPACT_CLEAR_ACTIONS: - case OFPACT_SAMPLE: - return false; - - case OFPACT_POP_MPLS: - case OFPACT_DEC_MPLS_TTL: - case OFPACT_SET_MPLS_TTL: - case OFPACT_SET_MPLS_TC: - case OFPACT_SET_MPLS_LABEL: - case OFPACT_SET_IPV4_SRC: - case OFPACT_SET_IPV4_DST: - case OFPACT_SET_IP_DSCP: - case OFPACT_SET_IP_ECN: - case OFPACT_SET_IP_TTL: - case OFPACT_SET_L4_SRC_PORT: - case OFPACT_SET_L4_DST_PORT: - case OFPACT_RESUBMIT: - case OFPACT_STACK_PUSH: - case OFPACT_STACK_POP: - case OFPACT_DEC_TTL: - case OFPACT_MULTIPATH: - case OFPACT_BUNDLE: - case OFPACT_LEARN: - case OFPACT_FIN_TIMEOUT: - case OFPACT_GOTO_TABLE: - return true; - - case OFPACT_REG_MOVE: - return (mf_is_l3_or_higher(ofpact_get_REG_MOVE(a)->dst.field) || - mf_is_l3_or_higher(ofpact_get_REG_MOVE(a)->src.field)); - - case OFPACT_SET_FIELD: - return mf_is_l3_or_higher(ofpact_get_SET_FIELD(a)->field); - - case OFPACT_PUSH_MPLS: - /* Recirculate if it is an IP packet with a zero ttl. This may - * indicate that the packet was previously MPLS and an MPLS pop action - * converted it to IP. In this case recirculating should reveal the IP - * TTL which is used as the basis for a new MPLS LSE. */ - return (!flow_count_mpls_labels(flow, wc) - && flow->nw_ttl == 0 - && is_ip_any(flow)); - } - - OVS_NOT_REACHED(); -} - static void recirc_put_unroll_xlate(struct xlate_ctx *ctx) { @@ -4138,6 +4074,16 @@ recirc_unroll_actions(const struct ofpact *ofpacts, size_t ofpacts_len, } } +#define CHECK_MPLS_RECIRCULATION() \ + if (ctx->was_mpls) { \ + ctx_trigger_recirculation(ctx); \ + break; \ + } +#define CHECK_MPLS_RECIRCULATION_IF(COND) \ + if (COND) { \ + CHECK_MPLS_RECIRCULATION(); \ + } + static void do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, struct xlate_ctx *ctx) @@ -4157,11 +4103,6 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, const struct ofpact_set_field *set_field; const struct mf_field *mf; - if (!ctx->exit && ofpact_needs_recirculation_after_mpls(a, ctx)) { - ctx->exit = true; - ctx->recirc_action_offset = ctx->action_set.size; - } - if (ctx->exit) { /* Check if need to store the remaining actions for later * execution. */ @@ -4182,6 +4123,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, case OFPACT_GROUP: if (xlate_group_action(ctx, ofpact_get_GROUP(a)->group_id)) { + /* Group could not be found. */ return; } break; @@ -4241,6 +4183,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, break; case OFPACT_SET_IPV4_SRC: + CHECK_MPLS_RECIRCULATION(); if (flow->dl_type == htons(ETH_TYPE_IP)) { memset(&wc->masks.nw_src, 0xff, sizeof wc->masks.nw_src); flow->nw_src = ofpact_get_SET_IPV4_SRC(a)->ipv4; @@ -4248,6 +4191,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, break; case OFPACT_SET_IPV4_DST: + CHECK_MPLS_RECIRCULATION(); if (flow->dl_type == htons(ETH_TYPE_IP)) { memset(&wc->masks.nw_dst, 0xff, sizeof wc->masks.nw_dst); flow->nw_dst = ofpact_get_SET_IPV4_DST(a)->ipv4; @@ -4255,6 +4199,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, break; case OFPACT_SET_IP_DSCP: + CHECK_MPLS_RECIRCULATION(); if (is_ip_any(flow)) { wc->masks.nw_tos |= IP_DSCP_MASK; flow->nw_tos &= ~IP_DSCP_MASK; @@ -4263,6 +4208,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, break; case OFPACT_SET_IP_ECN: + CHECK_MPLS_RECIRCULATION(); if (is_ip_any(flow)) { wc->masks.nw_tos |= IP_ECN_MASK; flow->nw_tos &= ~IP_ECN_MASK; @@ -4271,6 +4217,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, break; case OFPACT_SET_IP_TTL: + CHECK_MPLS_RECIRCULATION(); if (is_ip_any(flow)) { wc->masks.nw_ttl = 0xff; flow->nw_ttl = ofpact_get_SET_IP_TTL(a)->ttl; @@ -4278,6 +4225,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, break; case OFPACT_SET_L4_SRC_PORT: + CHECK_MPLS_RECIRCULATION(); if (is_ip_any(flow) && !(flow->nw_frag & FLOW_NW_FRAG_LATER)) { memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto); memset(&wc->masks.tp_src, 0xff, sizeof wc->masks.tp_src); @@ -4286,6 +4234,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, break; case OFPACT_SET_L4_DST_PORT: + CHECK_MPLS_RECIRCULATION(); if (is_ip_any(flow) && !(flow->nw_frag & FLOW_NW_FRAG_LATER)) { memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto); memset(&wc->masks.tp_dst, 0xff, sizeof wc->masks.tp_dst); @@ -4314,10 +4263,15 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, break; case OFPACT_REG_MOVE: + CHECK_MPLS_RECIRCULATION_IF( + mf_is_l3_or_higher(ofpact_get_REG_MOVE(a)->dst.field) || + mf_is_l3_or_higher(ofpact_get_REG_MOVE(a)->src.field)); nxm_execute_reg_move(ofpact_get_REG_MOVE(a), flow, wc); break; case OFPACT_SET_FIELD: + CHECK_MPLS_RECIRCULATION_IF( + mf_is_l3_or_higher(ofpact_get_SET_FIELD(a)->field)); set_field = ofpact_get_SET_FIELD(a); mf = set_field->field; @@ -4343,43 +4297,62 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, break; case OFPACT_STACK_PUSH: + CHECK_MPLS_RECIRCULATION_IF( + mf_is_l3_or_higher(ofpact_get_STACK_PUSH(a)->subfield.field)); nxm_execute_stack_push(ofpact_get_STACK_PUSH(a), flow, wc, &ctx->stack); break; case OFPACT_STACK_POP: + CHECK_MPLS_RECIRCULATION_IF( + mf_is_l3_or_higher(ofpact_get_STACK_POP(a)->subfield.field)); nxm_execute_stack_pop(ofpact_get_STACK_POP(a), flow, wc, &ctx->stack); break; case OFPACT_PUSH_MPLS: + /* Recirculate if it is an IP packet with a zero ttl. This may + * indicate that the packet was previously MPLS and an MPLS pop + * action converted it to IP. In this case recirculating should + * reveal the IP TTL which is used as the basis for a new MPLS + * LSE. */ + CHECK_MPLS_RECIRCULATION_IF( + !flow_count_mpls_labels(flow, wc) + && flow->nw_ttl == 0 + && is_ip_any(flow)); compose_mpls_push_action(ctx, ofpact_get_PUSH_MPLS(a)); break; case OFPACT_POP_MPLS: + CHECK_MPLS_RECIRCULATION(); compose_mpls_pop_action(ctx, ofpact_get_POP_MPLS(a)->ethertype); break; case OFPACT_SET_MPLS_LABEL: + CHECK_MPLS_RECIRCULATION(); compose_set_mpls_label_action( ctx, ofpact_get_SET_MPLS_LABEL(a)->label); - break; + break; case OFPACT_SET_MPLS_TC: + CHECK_MPLS_RECIRCULATION(); compose_set_mpls_tc_action(ctx, ofpact_get_SET_MPLS_TC(a)->tc); break; case OFPACT_SET_MPLS_TTL: + CHECK_MPLS_RECIRCULATION(); compose_set_mpls_ttl_action(ctx, ofpact_get_SET_MPLS_TTL(a)->ttl); break; case OFPACT_DEC_MPLS_TTL: + CHECK_MPLS_RECIRCULATION(); if (compose_dec_mpls_ttl_action(ctx)) { return; } break; case OFPACT_DEC_TTL: + CHECK_MPLS_RECIRCULATION(); wc->masks.nw_ttl = 0xff; if (compose_dec_ttl(ctx, ofpact_get_DEC_TTL(a))) { return; @@ -4391,10 +4364,12 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, break; case OFPACT_MULTIPATH: + CHECK_MPLS_RECIRCULATION(); multipath_execute(ofpact_get_MULTIPATH(a), flow, wc); break; case OFPACT_BUNDLE: + CHECK_MPLS_RECIRCULATION(); xlate_bundle_action(ctx, ofpact_get_BUNDLE(a)); break; @@ -4403,6 +4378,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, break; case OFPACT_LEARN: + CHECK_MPLS_RECIRCULATION(); xlate_learn_action(ctx, ofpact_get_LEARN(a)); break; @@ -4429,6 +4405,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, break; } case OFPACT_FIN_TIMEOUT: + CHECK_MPLS_RECIRCULATION(); memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto); ctx->xout->has_fin_timeout = true; xlate_fin_timeout(ctx, ofpact_get_FIN_TIMEOUT(a)); @@ -4472,6 +4449,16 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, xlate_sample_action(ctx, ofpact_get_SAMPLE(a)); break; } + + /* Check if need to store this and the remaining actions for later + * execution. */ + if (ctx->exit && ctx_first_recirculation_action(ctx)) { + recirc_unroll_actions(a, OFPACT_ALIGN(ofpacts_len - + ((uint8_t *)a - + (uint8_t *)ofpacts)), + ctx); + break; + } } } -- cgit v1.2.1 From aa63bc9de230f688692831ee9719a0b9b5eddc6b Mon Sep 17 00:00:00 2001 From: Sorin Vinturis Date: Thu, 26 Mar 2015 19:59:36 +0000 Subject: datapath-windows: Support for allocating/releasing memory with tag Added functions for allocating and releasing memory with specified tag. Signed-off-by: Sorin Vinturis Reported-by: Alin Gabriel Serdean Reported-at: https://github.com/openvswitch/ovs-issues/issues/56 Acked-by: Alin Gabriel Serdean Acked-by: Eitan Eliahu Signed-off-by: Ben Pfaff --- datapath-windows/ovsext/Util.c | 15 +++++++++++++++ datapath-windows/ovsext/Util.h | 2 ++ 2 files changed, 17 insertions(+) diff --git a/datapath-windows/ovsext/Util.c b/datapath-windows/ovsext/Util.c index 2dfba8e3a..65dd1327a 100644 --- a/datapath-windows/ovsext/Util.c +++ b/datapath-windows/ovsext/Util.c @@ -24,6 +24,21 @@ extern NDIS_HANDLE gOvsExtDriverHandle; +VOID* +OvsAllocateMemoryWithTag(size_t size, ULONG tag) +{ + OVS_VERIFY_IRQL_LE(DISPATCH_LEVEL); + return NdisAllocateMemoryWithTagPriority(gOvsExtDriverHandle, + (UINT32)size, tag, NormalPoolPriority); +} + +VOID +OvsFreeMemoryWithTag(VOID *ptr, ULONG tag) +{ + ASSERT(ptr); + NdisFreeMemoryWithTagPriority(gOvsExtDriverHandle, ptr, tag); +} + VOID * OvsAllocateMemory(size_t size) { diff --git a/datapath-windows/ovsext/Util.h b/datapath-windows/ovsext/Util.h index e75220931..0303f46e6 100644 --- a/datapath-windows/ovsext/Util.h +++ b/datapath-windows/ovsext/Util.h @@ -25,8 +25,10 @@ #define OVS_OTHER_POOL_TAG 'MSVO' VOID *OvsAllocateMemory(size_t size); +VOID *OvsAllocateMemoryWithTag(size_t size, ULONG tag); VOID *OvsAllocateAlignedMemory(size_t size, UINT16 align); VOID OvsFreeMemory(VOID *ptr); +VOID OvsFreeMemoryWithTag(VOID *ptr, ULONG tag); VOID OvsFreeAlignedMemory(VOID *ptr); #define LIST_FORALL(_headPtr, _itemPtr) \ -- cgit v1.2.1 From 5bf619159c26044b5643a50ec83aaa7de5b52aef Mon Sep 17 00:00:00 2001 From: Sorin Vinturis Date: Thu, 26 Mar 2015 19:59:36 +0000 Subject: datapath-windows: Added specific pool tag for datapath code All memory allocations within datapath code have 'DSVO' pool tag. Signed-off-by: Sorin Vinturis Reported-by: Alin Gabriel Serdean Reported-at: https://github.com/openvswitch/ovs-issues/issues/56 Acked-by: Alin Gabriel Serdean Acked-by: Eitan Eliahu Signed-off-by: Ben Pfaff --- datapath-windows/ovsext/Datapath.c | 38 +++++++++++++++++++++++++++++++++++--- datapath-windows/ovsext/Datapath.h | 31 +++---------------------------- datapath-windows/ovsext/Util.h | 1 + 3 files changed, 39 insertions(+), 31 deletions(-) diff --git a/datapath-windows/ovsext/Datapath.c b/datapath-windows/ovsext/Datapath.c index c6fe89eb7..888c6ef79 100644 --- a/datapath-windows/ovsext/Datapath.c +++ b/datapath-windows/ovsext/Datapath.c @@ -349,6 +349,37 @@ extern POVS_SWITCH_CONTEXT gOvsSwitchContext; NDIS_SPIN_LOCK ovsCtrlLockObj; PNDIS_SPIN_LOCK gOvsCtrlLock; +NTSTATUS +InitUserDumpState(POVS_OPEN_INSTANCE instance, + POVS_MESSAGE ovsMsg) +{ + /* Clear the dumpState from a previous dump sequence. */ + ASSERT(instance->dumpState.ovsMsg == NULL); + ASSERT(ovsMsg); + + instance->dumpState.ovsMsg = + (POVS_MESSAGE)OvsAllocateMemoryWithTag(sizeof(OVS_MESSAGE), + OVS_DATAPATH_POOL_TAG); + if (instance->dumpState.ovsMsg == NULL) { + return STATUS_NO_MEMORY; + } + RtlCopyMemory(instance->dumpState.ovsMsg, ovsMsg, + sizeof *instance->dumpState.ovsMsg); + RtlZeroMemory(instance->dumpState.index, + sizeof instance->dumpState.index); + + return STATUS_SUCCESS; +} + +VOID +FreeUserDumpState(POVS_OPEN_INSTANCE instance) +{ + if (instance->dumpState.ovsMsg != NULL) { + OvsFreeMemoryWithTag(instance->dumpState.ovsMsg, + OVS_DATAPATH_POOL_TAG); + RtlZeroMemory(&instance->dumpState, sizeof instance->dumpState); + } +} VOID OvsInit() @@ -497,7 +528,8 @@ OvsAddOpenInstance(POVS_DEVICE_EXTENSION ovsExt, PFILE_OBJECT fileObject) { POVS_OPEN_INSTANCE instance = - (POVS_OPEN_INSTANCE) OvsAllocateMemory(sizeof (OVS_OPEN_INSTANCE)); + (POVS_OPEN_INSTANCE)OvsAllocateMemoryWithTag(sizeof(OVS_OPEN_INSTANCE), + OVS_DATAPATH_POOL_TAG); UINT32 i; if (instance == NULL) { @@ -508,7 +540,7 @@ OvsAddOpenInstance(POVS_DEVICE_EXTENSION ovsExt, if (ovsNumberOfOpenInstances >= OVS_MAX_OPEN_INSTANCES) { OvsReleaseCtrlLock(); - OvsFreeMemory(instance); + OvsFreeMemoryWithTag(instance, OVS_DATAPATH_POOL_TAG); return STATUS_INSUFFICIENT_RESOURCES; } RtlZeroMemory(instance, sizeof (OVS_OPEN_INSTANCE)); @@ -559,7 +591,7 @@ OvsRemoveOpenInstance(PFILE_OBJECT fileObject) OvsReleaseCtrlLock(); ASSERT(instance->eventQueue == NULL); ASSERT (instance->packetQueue == NULL); - OvsFreeMemory(instance); + OvsFreeMemoryWithTag(instance, OVS_DATAPATH_POOL_TAG); } NTSTATUS diff --git a/datapath-windows/ovsext/Datapath.h b/datapath-windows/ovsext/Datapath.h index ba31ece4b..863afc4ca 100644 --- a/datapath-windows/ovsext/Datapath.h +++ b/datapath-windows/ovsext/Datapath.h @@ -129,35 +129,10 @@ InitUserParamsCtx(PIRP irp, usrParamsCtx->outputLength = outputLength; } -static __inline NTSTATUS -InitUserDumpState(POVS_OPEN_INSTANCE instance, - POVS_MESSAGE ovsMsg) -{ - /* Clear the dumpState from a previous dump sequence. */ - ASSERT(instance->dumpState.ovsMsg == NULL); - ASSERT(ovsMsg); - - instance->dumpState.ovsMsg = - (POVS_MESSAGE) OvsAllocateMemory(sizeof (OVS_MESSAGE)); - if (instance->dumpState.ovsMsg == NULL) { - return STATUS_NO_MEMORY; - } - RtlCopyMemory(instance->dumpState.ovsMsg, ovsMsg, - sizeof *instance->dumpState.ovsMsg); - RtlZeroMemory(instance->dumpState.index, - sizeof instance->dumpState.index); - - return STATUS_SUCCESS; -} +NTSTATUS InitUserDumpState(POVS_OPEN_INSTANCE instance, + POVS_MESSAGE ovsMsg); -static __inline VOID -FreeUserDumpState(POVS_OPEN_INSTANCE instance) -{ - if (instance->dumpState.ovsMsg != NULL) { - OvsFreeMemory(instance->dumpState.ovsMsg); - RtlZeroMemory(&instance->dumpState, sizeof instance->dumpState); - } -} +VOID FreeUserDumpState(POVS_OPEN_INSTANCE instance); NTSTATUS OvsSetupDumpStart(POVS_USER_PARAMS_CONTEXT usrParamsCtx); diff --git a/datapath-windows/ovsext/Util.h b/datapath-windows/ovsext/Util.h index 0303f46e6..0f326545b 100644 --- a/datapath-windows/ovsext/Util.h +++ b/datapath-windows/ovsext/Util.h @@ -23,6 +23,7 @@ #define OVS_NBL_ONLY_POOL_TAG 'OSVO' #define OVS_NET_BUFFER_POOL_TAG 'NSVO' #define OVS_OTHER_POOL_TAG 'MSVO' +#define OVS_DATAPATH_POOL_TAG 'DSVO' VOID *OvsAllocateMemory(size_t size); VOID *OvsAllocateMemoryWithTag(size_t size, ULONG tag); -- cgit v1.2.1 From 48b3e646d13f96d7d4d256966ae56910a557ed19 Mon Sep 17 00:00:00 2001 From: Sorin Vinturis Date: Thu, 26 Mar 2015 19:59:36 +0000 Subject: datapath-windows: Added specific pool tag for buffermgmt code All MDL memory allocations within buffermgmt code have 'BSVO' pool tag. Signed-off-by: Sorin Vinturis Reported-by: Alin Gabriel Serdean Reported-at: https://github.com/openvswitch/ovs-issues/issues/56 Acked-by: Alin Gabriel Serdean Acked-by: Eitan Eliahu Signed-off-by: Ben Pfaff --- datapath-windows/ovsext/BufferMgmt.c | 6 +++--- datapath-windows/ovsext/Util.h | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/datapath-windows/ovsext/BufferMgmt.c b/datapath-windows/ovsext/BufferMgmt.c index e0377c13a..572b2988a 100644 --- a/datapath-windows/ovsext/BufferMgmt.c +++ b/datapath-windows/ovsext/BufferMgmt.c @@ -433,14 +433,14 @@ OvsAllocateMDLAndData(NDIS_HANDLE ndisHandle, PMDL mdl; PVOID data; - data = OvsAllocateMemory(dataSize); + data = OvsAllocateMemoryWithTag(dataSize, OVS_MDL_POOL_TAG); if (data == NULL) { return NULL; } mdl = NdisAllocateMdl(ndisHandle, data, dataSize); if (mdl == NULL) { - OvsFreeMemory(data); + OvsFreeMemoryWithTag(data, OVS_MDL_POOL_TAG); } return mdl; @@ -454,7 +454,7 @@ OvsFreeMDLAndData(PMDL mdl) data = MmGetMdlVirtualAddress(mdl); NdisFreeMdl(mdl); - OvsFreeMemory(data); + OvsFreeMemoryWithTag(data, OVS_MDL_POOL_TAG); } diff --git a/datapath-windows/ovsext/Util.h b/datapath-windows/ovsext/Util.h index 0f326545b..6a9c16994 100644 --- a/datapath-windows/ovsext/Util.h +++ b/datapath-windows/ovsext/Util.h @@ -23,6 +23,7 @@ #define OVS_NBL_ONLY_POOL_TAG 'OSVO' #define OVS_NET_BUFFER_POOL_TAG 'NSVO' #define OVS_OTHER_POOL_TAG 'MSVO' +#define OVS_MDL_POOL_TAG 'BSVO' #define OVS_DATAPATH_POOL_TAG 'DSVO' VOID *OvsAllocateMemory(size_t size); -- cgit v1.2.1 From 84726095b13af12d34161842691c3e5a05fc8d20 Mon Sep 17 00:00:00 2001 From: Sorin Vinturis Date: Thu, 26 Mar 2015 19:59:36 +0000 Subject: datapath-windows: Added specific pool tag for event code All memory allocations within event code have 'ESVO' pool tag. Signed-off-by: Sorin Vinturis Reported-by: Alin Gabriel Serdean Reported-at: https://github.com/openvswitch/ovs-issues/issues/56 Acked-by: Alin Gabriel Serdean Acked-by: Eitan Eliahu Signed-off-by: Ben Pfaff --- datapath-windows/ovsext/Event.c | 18 ++++++++++-------- datapath-windows/ovsext/Util.h | 1 + 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/datapath-windows/ovsext/Event.c b/datapath-windows/ovsext/Event.c index 00f461609..cca9575b7 100644 --- a/datapath-windows/ovsext/Event.c +++ b/datapath-windows/ovsext/Event.c @@ -96,9 +96,9 @@ OvsCleanupEvent(POVS_OPEN_INSTANCE instance) LIST_FORALL_SAFE(&queue->elemList, link, next) { elem = CONTAINING_RECORD(link, OVS_EVENT_QUEUE_ELEM, link); - OvsFreeMemory(elem); + OvsFreeMemoryWithTag(elem, OVS_EVENT_POOL_TAG); } - OvsFreeMemory(queue); + OvsFreeMemoryWithTag(queue, OVS_EVENT_POOL_TAG); } } @@ -139,7 +139,8 @@ OvsPostEvent(UINT32 portNo, portNo == OVS_DEFAULT_PORT_NO) { queue->pollAll = TRUE; } else { - elem = (POVS_EVENT_QUEUE_ELEM)OvsAllocateMemory(sizeof(*elem)); + elem = (POVS_EVENT_QUEUE_ELEM)OvsAllocateMemoryWithTag( + sizeof(*elem), OVS_EVENT_POOL_TAG); if (elem == NULL) { queue->pollAll = TRUE; } else { @@ -158,7 +159,7 @@ OvsPostEvent(UINT32 portNo, LIST_FORALL_SAFE(&queue->elemList, curr, next) { RemoveEntryList(curr); elem = CONTAINING_RECORD(curr, OVS_EVENT_QUEUE_ELEM, link); - OvsFreeMemory(elem); + OvsFreeMemoryWithTag(elem, OVS_EVENT_POOL_TAG); } queue->numElems = 0; } @@ -243,7 +244,8 @@ OvsSubscribeEventIoctl(PFILE_OBJECT fileObject, } if (request->subscribe) { - queue = (POVS_EVENT_QUEUE)OvsAllocateMemory(sizeof (OVS_EVENT_QUEUE)); + queue = (POVS_EVENT_QUEUE)OvsAllocateMemoryWithTag( + sizeof(OVS_EVENT_QUEUE), OVS_EVENT_POOL_TAG); if (queue == NULL) { status = STATUS_NO_MEMORY; OVS_LOG_WARN("Fail to allocate event queue"); @@ -284,9 +286,9 @@ done_event_subscribe: } LIST_FORALL_SAFE(&queue->elemList, link, next) { elem = CONTAINING_RECORD(link, OVS_EVENT_QUEUE_ELEM, link); - OvsFreeMemory(elem); + OvsFreeMemoryWithTag(elem, OVS_EVENT_POOL_TAG); } - OvsFreeMemory(queue); + OvsFreeMemoryWithTag(queue, OVS_EVENT_POOL_TAG); } else { OvsReleaseEventQueueLock(); } @@ -446,7 +448,7 @@ OvsRemoveEventEntry(POVS_OPEN_INSTANCE instance, elem = (POVS_EVENT_QUEUE_ELEM)RemoveHeadList(&queue->elemList); entry->portNo = elem->portNo; entry->status = elem->status; - OvsFreeMemory(elem); + OvsFreeMemoryWithTag(elem, OVS_EVENT_POOL_TAG); queue->numElems--; status = STATUS_SUCCESS; } diff --git a/datapath-windows/ovsext/Util.h b/datapath-windows/ovsext/Util.h index 6a9c16994..78112889a 100644 --- a/datapath-windows/ovsext/Util.h +++ b/datapath-windows/ovsext/Util.h @@ -25,6 +25,7 @@ #define OVS_OTHER_POOL_TAG 'MSVO' #define OVS_MDL_POOL_TAG 'BSVO' #define OVS_DATAPATH_POOL_TAG 'DSVO' +#define OVS_EVENT_POOL_TAG 'ESVO' VOID *OvsAllocateMemory(size_t size); VOID *OvsAllocateMemoryWithTag(size_t size, ULONG tag); -- cgit v1.2.1 From 99075373dab5cdd0a4305e9e7036c9e125579e0a Mon Sep 17 00:00:00 2001 From: Sorin Vinturis Date: Thu, 26 Mar 2015 19:59:37 +0000 Subject: datapath-windows: Added specific pool tag for flow code All memory allocations within flow code have 'LSVO' pool tag. Signed-off-by: Sorin Vinturis Reported-by: Alin Gabriel Serdean Reported-at: https://github.com/openvswitch/ovs-issues/issues/56 Acked-by: Alin Gabriel Serdean Acked-by: Eitan Eliahu Signed-off-by: Ben Pfaff --- datapath-windows/ovsext/Flow.c | 11 ++++++----- datapath-windows/ovsext/Util.h | 1 + 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/datapath-windows/ovsext/Flow.c b/datapath-windows/ovsext/Flow.c index d3de8cc45..97220b468 100644 --- a/datapath-windows/ovsext/Flow.c +++ b/datapath-windows/ovsext/Flow.c @@ -1512,7 +1512,7 @@ OvsDeleteFlowTable(OVS_DATAPATH *datapath) } DeleteAllFlows(datapath); - OvsFreeMemory(datapath->flowTable); + OvsFreeMemoryWithTag(datapath->flowTable, OVS_FLOW_POOL_TAG); datapath->flowTable = NULL; NdisFreeRWLock(datapath->lock); @@ -1534,8 +1534,8 @@ OvsAllocateFlowTable(OVS_DATAPATH *datapath, PLIST_ENTRY bucket; int i; - datapath->flowTable = OvsAllocateMemory(OVS_FLOW_TABLE_SIZE * - sizeof (LIST_ENTRY)); + datapath->flowTable = OvsAllocateMemoryWithTag( + OVS_FLOW_TABLE_SIZE * sizeof(LIST_ENTRY), OVS_FLOW_POOL_TAG); if (!datapath->flowTable) { return NDIS_STATUS_RESOURCES; } @@ -1976,7 +1976,7 @@ VOID FreeFlow(OvsFlow *flow) { ASSERT(flow); - OvsFreeMemory(flow); + OvsFreeMemoryWithTag(flow, OVS_FLOW_POOL_TAG); } NTSTATUS @@ -2259,7 +2259,8 @@ OvsPrepareFlow(OvsFlow **flow, do { *flow = localFlow = - OvsAllocateMemory(sizeof(OvsFlow) + put->actionsLen); + OvsAllocateMemoryWithTag(sizeof(OvsFlow) + put->actionsLen, + OVS_FLOW_POOL_TAG); if (localFlow == NULL) { status = STATUS_NO_MEMORY; break; diff --git a/datapath-windows/ovsext/Util.h b/datapath-windows/ovsext/Util.h index 78112889a..907cd3c96 100644 --- a/datapath-windows/ovsext/Util.h +++ b/datapath-windows/ovsext/Util.h @@ -26,6 +26,7 @@ #define OVS_MDL_POOL_TAG 'BSVO' #define OVS_DATAPATH_POOL_TAG 'DSVO' #define OVS_EVENT_POOL_TAG 'ESVO' +#define OVS_FLOW_POOL_TAG 'LSVO' VOID *OvsAllocateMemory(size_t size); VOID *OvsAllocateMemoryWithTag(size_t size, ULONG tag); -- cgit v1.2.1 From cc26fc9215f551fafd6aa64dffcd8d111ac5a40c Mon Sep 17 00:00:00 2001 From: Sorin Vinturis Date: Thu, 26 Mar 2015 19:59:37 +0000 Subject: datapath-windows: Added specific pool tag for vxlan code All memory allocations within vxlan code have 'XSVO' pool tag. Signed-off-by: Sorin Vinturis Reported-by: Alin Gabriel Serdean Reported-at: https://github.com/openvswitch/ovs-issues/issues/56 Acked-by: Alin Gabriel Serdean Acked-by: Eitan Eliahu Signed-off-by: Ben Pfaff --- datapath-windows/ovsext/Util.h | 1 + datapath-windows/ovsext/Vxlan.c | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/datapath-windows/ovsext/Util.h b/datapath-windows/ovsext/Util.h index 907cd3c96..c153acf27 100644 --- a/datapath-windows/ovsext/Util.h +++ b/datapath-windows/ovsext/Util.h @@ -27,6 +27,7 @@ #define OVS_DATAPATH_POOL_TAG 'DSVO' #define OVS_EVENT_POOL_TAG 'ESVO' #define OVS_FLOW_POOL_TAG 'LSVO' +#define OVS_VXLAN_POOL_TAG 'XSVO' VOID *OvsAllocateMemory(size_t size); VOID *OvsAllocateMemoryWithTag(size_t size, ULONG tag); diff --git a/datapath-windows/ovsext/Vxlan.c b/datapath-windows/ovsext/Vxlan.c index 1ce5af249..8c5718506 100644 --- a/datapath-windows/ovsext/Vxlan.c +++ b/datapath-windows/ovsext/Vxlan.c @@ -59,7 +59,8 @@ OvsInitVxlanTunnel(POVS_VPORT_ENTRY vport, { POVS_VXLAN_VPORT vxlanPort; - vxlanPort = OvsAllocateMemory(sizeof (*vxlanPort)); + vxlanPort = OvsAllocateMemoryWithTag(sizeof (*vxlanPort), + OVS_VXLAN_POOL_TAG); if (vxlanPort == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } @@ -86,7 +87,7 @@ OvsCleanupVxlanTunnel(POVS_VPORT_ENTRY vport) return; } - OvsFreeMemory(vport->priv); + OvsFreeMemoryWithTag(vport->priv, OVS_VXLAN_POOL_TAG); vport->priv = NULL; } -- cgit v1.2.1 From f68ddba96638e82bb1c43a2649e08c94aef3cdff Mon Sep 17 00:00:00 2001 From: Sorin Vinturis Date: Thu, 26 Mar 2015 19:59:37 +0000 Subject: datapath-windows: Added specific pool tag for iphelper code All memory allocations within iphelper code have 'HSVO' pool tag. Signed-off-by: Sorin Vinturis Reported-by: Alin Gabriel Serdean Reported-at: https://github.com/openvswitch/ovs-issues/issues/56 Acked-by: Alin Gabriel Serdean Acked-by: Eitan Eliahu Signed-off-by: Ben Pfaff --- datapath-windows/ovsext/IpHelper.c | 70 ++++++++++++++++++++------------------ datapath-windows/ovsext/Util.h | 1 + 2 files changed, 37 insertions(+), 34 deletions(-) diff --git a/datapath-windows/ovsext/IpHelper.c b/datapath-windows/ovsext/IpHelper.c index 0c64be44b..de0d4579a 100644 --- a/datapath-windows/ovsext/IpHelper.c +++ b/datapath-windows/ovsext/IpHelper.c @@ -777,7 +777,8 @@ OvsCreateIPNeighEntry(PMIB_IPNET_ROW2 ipNeigh) UINT64 timeVal; ASSERT(ipNeigh != NULL); - entry = (POVS_IPNEIGH_ENTRY)OvsAllocateMemory(sizeof (OVS_IPNEIGH_ENTRY)); + entry = (POVS_IPNEIGH_ENTRY)OvsAllocateMemoryWithTag( + sizeof(OVS_IPNEIGH_ENTRY), OVS_IPHELPER_POOL_TAG); if (entry == NULL) { return NULL; } @@ -802,8 +803,8 @@ OvsCreateIPForwardEntry(PMIB_IPFORWARD_ROW2 ipRoute) ASSERT(ipRoute); - entry = - (POVS_IPFORWARD_ENTRY)OvsAllocateMemory(sizeof (OVS_IPFORWARD_ENTRY)); + entry = (POVS_IPFORWARD_ENTRY)OvsAllocateMemoryWithTag( + sizeof(OVS_IPFORWARD_ENTRY), OVS_IPHELPER_POOL_TAG); if (entry == NULL) { return NULL; } @@ -823,7 +824,8 @@ OvsCreateFwdEntry(POVS_FWD_INFO fwdInfo) { POVS_FWD_ENTRY entry; - entry = (POVS_FWD_ENTRY)OvsAllocateMemory(sizeof (OVS_FWD_ENTRY)); + entry = (POVS_FWD_ENTRY)OvsAllocateMemoryWithTag( + sizeof(OVS_FWD_ENTRY), OVS_IPHELPER_POOL_TAG); if (entry == NULL) { return NULL; } @@ -855,7 +857,7 @@ OvsRemoveFwdEntry(POVS_FWD_ENTRY fwdEntry) if (ipf->refCount == 0) { ASSERT(IsListEmpty(&ipf->fwdList)); RemoveEntryList(&ipf->link); - OvsFreeMemory(ipf); + OvsFreeMemoryWithTag(ipf, OVS_IPHELPER_POOL_TAG); } if (ipn->refCount == 0) { @@ -864,10 +866,10 @@ OvsRemoveFwdEntry(POVS_FWD_ENTRY fwdEntry) NdisAcquireSpinLock(&ovsIpHelperLock); RemoveEntryList(&ipn->slink); NdisReleaseSpinLock(&ovsIpHelperLock); - OvsFreeMemory(ipn); + OvsFreeMemoryWithTag(ipn, OVS_IPHELPER_POOL_TAG); } - OvsFreeMemory(fwdEntry); + OvsFreeMemoryWithTag(fwdEntry, OVS_IPHELPER_POOL_TAG); } @@ -886,7 +888,7 @@ OvsRemoveIPForwardEntry(POVS_IPFORWARD_ENTRY ipf) ASSERT(ipf->refCount == 1); RemoveEntryList(&ipf->link); - OvsFreeMemory(ipf); + OvsFreeMemoryWithTag(ipf, OVS_IPHELPER_POOL_TAG); } @@ -908,7 +910,7 @@ OvsRemoveIPNeighEntry(POVS_IPNEIGH_ENTRY ipn) NdisAcquireSpinLock(&ovsIpHelperLock); RemoveEntryList(&ipn->slink); NdisReleaseSpinLock(&ovsIpHelperLock); - OvsFreeMemory(ipn); + OvsFreeMemoryWithTag(ipn, OVS_IPHELPER_POOL_TAG); } } @@ -1041,7 +1043,7 @@ OvsCleanupIpHelperRequestList(VOID) STATUS_DEVICE_NOT_READY, NULL); } - OvsFreeMemory(request); + OvsFreeMemoryWithTag(request, OVS_IPHELPER_POOL_TAG); } } @@ -1076,8 +1078,8 @@ OvsInternalAdapterUp(UINT32 portNo, RtlCopyMemory(&ovsInternalNetCfgId, netCfgInstanceId, sizeof (GUID)); RtlZeroMemory(&ovsInternalRow, sizeof (MIB_IF_ROW2)); - request = - (POVS_IP_HELPER_REQUEST)OvsAllocateMemory(sizeof (OVS_IP_HELPER_REQUEST)); + request = (POVS_IP_HELPER_REQUEST)OvsAllocateMemoryWithTag( + sizeof(OVS_IP_HELPER_REQUEST), OVS_IPHELPER_POOL_TAG); if (request == NULL) { OVS_LOG_ERROR("Fail to initialize Internal Adapter"); return; @@ -1103,7 +1105,7 @@ OvsHandleInternalAdapterUp(POVS_IP_HELPER_REQUEST request) MIB_UNICASTIPADDRESS_ROW ipEntry; GUID *netCfgInstanceId = &ovsInternalNetCfgId; - OvsFreeMemory(request); + OvsFreeMemoryWithTag(request, OVS_IPHELPER_POOL_TAG); status = OvsGetIfEntry(&ovsInternalNetCfgId, &ovsInternalRow); @@ -1161,7 +1163,7 @@ OvsEnqueueIpHelperRequest(POVS_IP_HELPER_REQUEST request) if (ovsInternalPortNo == OVS_DEFAULT_PORT_NO || ovsInternalIPConfigured == FALSE) { NdisReleaseSpinLock(&ovsIpHelperLock); - OvsFreeMemory(request); + OvsFreeMemoryWithTag(request, OVS_IPHELPER_POOL_TAG); return STATUS_NDIS_ADAPTER_NOT_READY; } else { InsertHeadList(&ovsIpHelperRequestList, &request->link); @@ -1185,8 +1187,8 @@ OvsFwdIPHelperRequest(PNET_BUFFER_LIST nbl, { POVS_IP_HELPER_REQUEST request; - request = - (POVS_IP_HELPER_REQUEST)OvsAllocateMemory(sizeof (OVS_IP_HELPER_REQUEST)); + request = (POVS_IP_HELPER_REQUEST)OvsAllocateMemoryWithTag( + sizeof(OVS_IP_HELPER_REQUEST), OVS_IPHELPER_POOL_TAG); if (request == NULL) { return STATUS_INSUFFICIENT_RESOURCES; @@ -1328,15 +1330,15 @@ fwd_handle_nbl: if (status != STATUS_SUCCESS) { if (newFWD) { ASSERT(fwdEntry != NULL); - OvsFreeMemory(fwdEntry); + OvsFreeMemoryWithTag(fwdEntry, OVS_IPHELPER_POOL_TAG); } if (newIPF) { ASSERT(ipf && ipf->refCount == 0); - OvsFreeMemory(ipf); + OvsFreeMemoryWithTag(ipf, OVS_IPHELPER_POOL_TAG); } if (newIPN) { ASSERT(ipn && ipn->refCount == 0); - OvsFreeMemory(ipn); + OvsFreeMemoryWithTag(ipn, OVS_IPHELPER_POOL_TAG); } ipAddr = request->fwdReq.tunnelKey.dst; OVS_LOG_INFO("Fail to handle IP helper request for dst: %d.%d.%d.%d", @@ -1352,7 +1354,7 @@ fwd_handle_nbl: status, status == STATUS_SUCCESS ? &fwdInfo : NULL); } - OvsFreeMemory(request); + OvsFreeMemoryWithTag(request, OVS_IPHELPER_POOL_TAG); } @@ -1477,7 +1479,7 @@ OvsStartIpHelper(PVOID data) OvsHandleFwdRequest(req); break; default: - OvsFreeMemory(req); + OvsFreeMemoryWithTag(req, OVS_IPHELPER_POOL_TAG); } NdisAcquireSpinLock(&ovsIpHelperLock); } @@ -1539,14 +1541,14 @@ OvsInitIpHelper(NDIS_HANDLE ndisFilterHandle) HANDLE threadHandle; UINT32 i; - ovsFwdHashTable = (PLIST_ENTRY)OvsAllocateMemory(sizeof(LIST_ENTRY) * - OVS_FWD_HASH_TABLE_SIZE); + ovsFwdHashTable = (PLIST_ENTRY)OvsAllocateMemoryWithTag( + sizeof(LIST_ENTRY) * OVS_FWD_HASH_TABLE_SIZE, OVS_IPHELPER_POOL_TAG); - ovsRouteHashTable = (PLIST_ENTRY)OvsAllocateMemory(sizeof(LIST_ENTRY) * - OVS_ROUTE_HASH_TABLE_SIZE); + ovsRouteHashTable = (PLIST_ENTRY)OvsAllocateMemoryWithTag( + sizeof(LIST_ENTRY) * OVS_ROUTE_HASH_TABLE_SIZE, OVS_IPHELPER_POOL_TAG); - ovsNeighHashTable = (PLIST_ENTRY)OvsAllocateMemory(sizeof(LIST_ENTRY) * - OVS_NEIGH_HASH_TABLE_SIZE); + ovsNeighHashTable = (PLIST_ENTRY)OvsAllocateMemoryWithTag( + sizeof(LIST_ENTRY) * OVS_NEIGH_HASH_TABLE_SIZE, OVS_IPHELPER_POOL_TAG); RtlZeroMemory(&ovsInternalRow, sizeof(MIB_IF_ROW2)); RtlZeroMemory(&ovsInternalIPRow, sizeof (MIB_IPINTERFACE_ROW)); @@ -1609,15 +1611,15 @@ init_cleanup: if (status != STATUS_SUCCESS) { OvsCancelChangeNotification(); if (ovsFwdHashTable) { - OvsFreeMemory(ovsFwdHashTable); + OvsFreeMemoryWithTag(ovsFwdHashTable, OVS_IPHELPER_POOL_TAG); ovsFwdHashTable = NULL; } if (ovsRouteHashTable) { - OvsFreeMemory(ovsRouteHashTable); + OvsFreeMemoryWithTag(ovsRouteHashTable, OVS_IPHELPER_POOL_TAG); ovsRouteHashTable = NULL; } if (ovsNeighHashTable) { - OvsFreeMemory(ovsNeighHashTable); + OvsFreeMemoryWithTag(ovsNeighHashTable, OVS_IPHELPER_POOL_TAG); ovsNeighHashTable = NULL; } if (ovsTableLock) { @@ -1644,9 +1646,9 @@ OvsCleanupIpHelper(VOID) KernelMode, FALSE, NULL); ObDereferenceObject(ovsIpHelperThreadContext.threadObject); - OvsFreeMemory(ovsFwdHashTable); - OvsFreeMemory(ovsRouteHashTable); - OvsFreeMemory(ovsNeighHashTable); + OvsFreeMemoryWithTag(ovsFwdHashTable, OVS_IPHELPER_POOL_TAG); + OvsFreeMemoryWithTag(ovsRouteHashTable, OVS_IPHELPER_POOL_TAG); + OvsFreeMemoryWithTag(ovsNeighHashTable, OVS_IPHELPER_POOL_TAG); NdisFreeRWLock(ovsTableLock); NdisFreeSpinLock(&ovsIpHelperLock); @@ -1684,6 +1686,6 @@ OvsCancelFwdIpHelperRequest(PNET_BUFFER_LIST nbl) STATUS_DEVICE_NOT_READY, NULL); } - OvsFreeMemory(req); + OvsFreeMemoryWithTag(req, OVS_IPHELPER_POOL_TAG); } } diff --git a/datapath-windows/ovsext/Util.h b/datapath-windows/ovsext/Util.h index c153acf27..c410729e3 100644 --- a/datapath-windows/ovsext/Util.h +++ b/datapath-windows/ovsext/Util.h @@ -28,6 +28,7 @@ #define OVS_EVENT_POOL_TAG 'ESVO' #define OVS_FLOW_POOL_TAG 'LSVO' #define OVS_VXLAN_POOL_TAG 'XSVO' +#define OVS_IPHELPER_POOL_TAG 'HSVO' VOID *OvsAllocateMemory(size_t size); VOID *OvsAllocateMemoryWithTag(size_t size, ULONG tag); -- cgit v1.2.1 From 5b55d0abac9a20aeaf0820baf6b3954bf88efe58 Mon Sep 17 00:00:00 2001 From: Sorin Vinturis Date: Thu, 26 Mar 2015 19:59:37 +0000 Subject: datapath-windows: Added specific pool tag for oid code All memory allocations within oid code have 'ASVO' pool tag. Signed-off-by: Sorin Vinturis Reported-by: Alin Gabriel Serdean Reported-at: https://github.com/openvswitch/ovs-issues/issues/56 Acked-by: Alin Gabriel Serdean Acked-by: Eitan Eliahu Signed-off-by: Ben Pfaff --- datapath-windows/ovsext/Oid.c | 41 +++++++++++++++++++++++++++++------------ datapath-windows/ovsext/Oid.h | 3 +++ datapath-windows/ovsext/Util.h | 1 + 3 files changed, 33 insertions(+), 12 deletions(-) diff --git a/datapath-windows/ovsext/Oid.c b/datapath-windows/ovsext/Oid.c index 83fa1e306..ea187906d 100644 --- a/datapath-windows/ovsext/Oid.c +++ b/datapath-windows/ovsext/Oid.c @@ -605,7 +605,7 @@ OvsIssueOidRequest(POVS_SWITCH_CONTEXT switchContext, NDIS_STATUS status; PNDIS_OID_REQUEST oidRequest; POVS_OID_CONTEXT oidContext; - ULONG OvsExtOidRequestId = 'ISVO'; + ULONG OvsExtOidRequestId = 'ISVO'; DBG_UNREFERENCED_PARAMETER(inputSize); DBG_UNREFERENCED_PARAMETER(oidInputBuffer); @@ -617,15 +617,17 @@ OvsIssueOidRequest(POVS_SWITCH_CONTEXT switchContext, ASSERT(oidOutputBuffer == NULL || outputSize != 0); ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); - oidRequest = OvsAllocateMemory(sizeof *oidRequest); + oidRequest = OvsAllocateMemoryWithTag(sizeof *oidRequest, + OVS_OID_POOL_TAG); if (!oidRequest) { status = NDIS_STATUS_RESOURCES; goto done; } - oidContext = OvsAllocateMemory(sizeof *oidContext); + oidContext = OvsAllocateMemoryWithTag(sizeof *oidContext, + OVS_OID_POOL_TAG); if (!oidContext) { - OvsFreeMemory(oidRequest); + OvsFreeMemoryWithTag(oidRequest, OVS_OID_POOL_TAG); status = NDIS_STATUS_RESOURCES; goto done; } @@ -684,8 +686,8 @@ OvsIssueOidRequest(POVS_SWITCH_CONTEXT switchContext, status = oidContext->status; ASSERT(status != NDIS_STATUS_PENDING); - OvsFreeMemory(oidRequest); - OvsFreeMemory(oidContext); + OvsFreeMemoryWithTag(oidRequest, OVS_OID_POOL_TAG); + OvsFreeMemoryWithTag(oidContext, OVS_OID_POOL_TAG); done: OVS_LOG_TRACE("Exit: status %8x.", status); @@ -710,7 +712,8 @@ OvsQuerySwitchActivationComplete(POVS_SWITCH_CONTEXT switchContext, OVS_LOG_TRACE("Enter: switchContext: %p, switchActive: %p", switchContext, switchActive); - switchParams = OvsAllocateMemory(sizeof *switchParams); + switchParams = OvsAllocateMemoryWithTag(sizeof *switchParams, + OVS_OID_POOL_TAG); if (!switchParams) { status = NDIS_STATUS_RESOURCES; goto done; @@ -741,7 +744,7 @@ OvsQuerySwitchActivationComplete(POVS_SWITCH_CONTEXT switchContext, *switchActive = switchParams->IsActive; } - OvsFreeMemory(switchParams); + OvsFreeMemoryWithTag(switchParams, OVS_OID_POOL_TAG); done: OVS_LOG_TRACE("Exit: status %8x, switchActive: %d.", @@ -769,7 +772,7 @@ OvsGetPortsOnSwitch(POVS_SWITCH_CONTEXT switchContext, do { UINT32 reqdArraySize; - portArray = OvsAllocateMemory(arraySize); + portArray = OvsAllocateMemoryWithTag(arraySize, OVS_OID_POOL_TAG); if (!portArray) { status = NDIS_STATUS_RESOURCES; goto done; @@ -794,7 +797,7 @@ OvsGetPortsOnSwitch(POVS_SWITCH_CONTEXT switchContext, break; } - OvsFreeMemory(portArray); + OvsFreeMemoryWithTag(portArray, OVS_OID_POOL_TAG); arraySize = reqdArraySize; if (status != NDIS_STATUS_INVALID_LENGTH) { break; @@ -827,7 +830,7 @@ OvsGetNicsOnSwitch(POVS_SWITCH_CONTEXT switchContext, do { UINT32 reqdArraySize; - nicArray = OvsAllocateMemory(arraySize); + nicArray = OvsAllocateMemoryWithTag(arraySize, OVS_OID_POOL_TAG); if (!nicArray) { status = NDIS_STATUS_RESOURCES; goto done; @@ -852,7 +855,7 @@ OvsGetNicsOnSwitch(POVS_SWITCH_CONTEXT switchContext, break; } - OvsFreeMemory(nicArray); + OvsFreeMemoryWithTag(nicArray, OVS_OID_POOL_TAG); arraySize = reqdArraySize; if (status != NDIS_STATUS_INVALID_LENGTH) { break; @@ -863,3 +866,17 @@ done: OVS_LOG_TRACE("Exit: status %8x.", status); return status; } + +VOID OvsFreeSwitchPortsArray(PNDIS_SWITCH_PORT_ARRAY portsArray) +{ + if (portsArray) { + OvsFreeMemoryWithTag(portsArray, OVS_OID_POOL_TAG); + } +} + +VOID OvsFreeSwitchNicsArray(PNDIS_SWITCH_NIC_ARRAY nicsArray) +{ + if (nicsArray) { + OvsFreeMemoryWithTag(nicsArray, OVS_OID_POOL_TAG); + } +} diff --git a/datapath-windows/ovsext/Oid.h b/datapath-windows/ovsext/Oid.h index 88a3d7d04..ffa4d60cb 100644 --- a/datapath-windows/ovsext/Oid.h +++ b/datapath-windows/ovsext/Oid.h @@ -23,4 +23,7 @@ NDIS_STATUS OvsGetPortsOnSwitch(POVS_SWITCH_CONTEXT switchContext, PNDIS_SWITCH_PORT_ARRAY *portArrayOut); NDIS_STATUS OvsGetNicsOnSwitch(POVS_SWITCH_CONTEXT switchContext, PNDIS_SWITCH_NIC_ARRAY *nicArrayOut); +VOID OvsFreeSwitchPortsArray(PNDIS_SWITCH_PORT_ARRAY portsArray); +VOID OvsFreeSwitchNicsArray(PNDIS_SWITCH_NIC_ARRAY nicsArray); + #endif /* __OID_H_ */ diff --git a/datapath-windows/ovsext/Util.h b/datapath-windows/ovsext/Util.h index c410729e3..115f334f0 100644 --- a/datapath-windows/ovsext/Util.h +++ b/datapath-windows/ovsext/Util.h @@ -29,6 +29,7 @@ #define OVS_FLOW_POOL_TAG 'LSVO' #define OVS_VXLAN_POOL_TAG 'XSVO' #define OVS_IPHELPER_POOL_TAG 'HSVO' +#define OVS_OID_POOL_TAG 'ASVO' VOID *OvsAllocateMemory(size_t size); VOID *OvsAllocateMemoryWithTag(size_t size, ULONG tag); -- cgit v1.2.1 From ba7f9d9019b28ee3331893b1771aa239b0bed005 Mon Sep 17 00:00:00 2001 From: Sorin Vinturis Date: Thu, 26 Mar 2015 19:59:37 +0000 Subject: datapath-windows: Added specific pool tag for switch code All memory allocations within switch code have 'SSVO' pool tag. Signed-off-by: Sorin Vinturis Reported-by: Alin Gabriel Serdean Reported-at: https://github.com/openvswitch/ovs-issues/issues/56 Acked-by: Alin Gabriel Serdean Acked-by: Eitan Eliahu Signed-off-by: Ben Pfaff --- datapath-windows/ovsext/Switch.c | 53 +++++++++++++++++++++++----------------- datapath-windows/ovsext/Util.h | 1 + 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/datapath-windows/ovsext/Switch.c b/datapath-windows/ovsext/Switch.c index a228d8e3b..61a453183 100644 --- a/datapath-windows/ovsext/Switch.c +++ b/datapath-windows/ovsext/Switch.c @@ -168,8 +168,8 @@ OvsCreateSwitch(NDIS_HANDLE ndisFilterHandle, OVS_LOG_TRACE("Enter: Create switch object"); - switchContext = - (POVS_SWITCH_CONTEXT) OvsAllocateMemory(sizeof(OVS_SWITCH_CONTEXT)); + switchContext = (POVS_SWITCH_CONTEXT) OvsAllocateMemoryWithTag( + sizeof(OVS_SWITCH_CONTEXT), OVS_SWITCH_POOL_TAG); if (switchContext == NULL) { status = NDIS_STATUS_RESOURCES; goto create_switch_done; @@ -187,7 +187,7 @@ OvsCreateSwitch(NDIS_HANDLE ndisFilterHandle, if (status != NDIS_STATUS_SUCCESS) { OVS_LOG_ERROR("OvsExtAttach: Extension is running in " "non-switch environment."); - OvsFreeMemory(switchContext); + OvsFreeMemoryWithTag(switchContext, OVS_SWITCH_POOL_TAG); goto create_switch_done; } @@ -198,14 +198,14 @@ OvsCreateSwitch(NDIS_HANDLE ndisFilterHandle, status = OvsInitSwitchContext(switchContext); if (status != NDIS_STATUS_SUCCESS) { - OvsFreeMemory(switchContext); + OvsFreeMemoryWithTag(switchContext, OVS_SWITCH_POOL_TAG); goto create_switch_done; } status = OvsTunnelFilterInitialize(gOvsExtDriverObject); if (status != NDIS_STATUS_SUCCESS) { OvsUninitSwitchContext(switchContext); - OvsFreeMemory(switchContext); + OvsFreeMemoryWithTag(switchContext, OVS_SWITCH_POOL_TAG); goto create_switch_done; } *switchContextOut = switchContext; @@ -264,7 +264,7 @@ OvsDeleteSwitch(POVS_SWITCH_CONTEXT switchContext) OvsTunnelFilterUninitialize(gOvsExtDriverObject); OvsClearAllSwitchVports(switchContext); OvsUninitSwitchContext(switchContext); - OvsFreeMemory(switchContext); + OvsFreeMemoryWithTag(switchContext, OVS_SWITCH_POOL_TAG); } OVS_LOG_TRACE("Exit: deleted switch %p dpNo: %d", switchContext, dpNo); } @@ -358,14 +358,14 @@ OvsInitSwitchContext(POVS_SWITCH_CONTEXT switchContext) switchContext->dispatchLock = NdisAllocateRWLock(switchContext->NdisFilterHandle); - switchContext->portNoHashArray = (PLIST_ENTRY) - OvsAllocateMemory(sizeof(LIST_ENTRY) * OVS_MAX_VPORT_ARRAY_SIZE); - switchContext->ovsPortNameHashArray = (PLIST_ENTRY) - OvsAllocateMemory(sizeof (LIST_ENTRY) * OVS_MAX_VPORT_ARRAY_SIZE); - switchContext->portIdHashArray= (PLIST_ENTRY) - OvsAllocateMemory(sizeof (LIST_ENTRY) * OVS_MAX_VPORT_ARRAY_SIZE); - switchContext->pidHashArray = (PLIST_ENTRY) - OvsAllocateMemory(sizeof(LIST_ENTRY) * OVS_MAX_PID_ARRAY_SIZE); + switchContext->portNoHashArray = (PLIST_ENTRY)OvsAllocateMemoryWithTag( + sizeof(LIST_ENTRY) * OVS_MAX_VPORT_ARRAY_SIZE, OVS_SWITCH_POOL_TAG); + switchContext->ovsPortNameHashArray = (PLIST_ENTRY)OvsAllocateMemoryWithTag( + sizeof(LIST_ENTRY) * OVS_MAX_VPORT_ARRAY_SIZE, OVS_SWITCH_POOL_TAG); + switchContext->portIdHashArray= (PLIST_ENTRY)OvsAllocateMemoryWithTag( + sizeof(LIST_ENTRY) * OVS_MAX_VPORT_ARRAY_SIZE, OVS_SWITCH_POOL_TAG); + switchContext->pidHashArray = (PLIST_ENTRY)OvsAllocateMemoryWithTag( + sizeof(LIST_ENTRY) * OVS_MAX_PID_ARRAY_SIZE, OVS_SWITCH_POOL_TAG); status = OvsAllocateFlowTable(&switchContext->datapath, switchContext); if (status == NDIS_STATUS_SUCCESS) { @@ -381,17 +381,20 @@ OvsInitSwitchContext(POVS_SWITCH_CONTEXT switchContext) NdisFreeRWLock(switchContext->dispatchLock); } if (switchContext->portNoHashArray) { - OvsFreeMemory(switchContext->portNoHashArray); + OvsFreeMemoryWithTag(switchContext->portNoHashArray, + OVS_SWITCH_POOL_TAG); } if (switchContext->ovsPortNameHashArray) { - OvsFreeMemory(switchContext->ovsPortNameHashArray); + OvsFreeMemoryWithTag(switchContext->ovsPortNameHashArray, + OVS_SWITCH_POOL_TAG); } if (switchContext->portIdHashArray) { - OvsFreeMemory(switchContext->portIdHashArray); + OvsFreeMemoryWithTag(switchContext->portIdHashArray, + OVS_SWITCH_POOL_TAG); } - if (switchContext->pidHashArray) { - OvsFreeMemory(switchContext->pidHashArray); + OvsFreeMemoryWithTag(switchContext->pidHashArray, + OVS_SWITCH_POOL_TAG); } OvsDeleteFlowTable(&switchContext->datapath); @@ -437,13 +440,17 @@ OvsUninitSwitchContext(POVS_SWITCH_CONTEXT switchContext) NdisFreeRWLock(switchContext->dispatchLock); switchContext->dispatchLock = NULL; NdisFreeSpinLock(&(switchContext->pidHashLock)); - OvsFreeMemory(switchContext->ovsPortNameHashArray); + OvsFreeMemoryWithTag(switchContext->ovsPortNameHashArray, + OVS_SWITCH_POOL_TAG); switchContext->ovsPortNameHashArray = NULL; - OvsFreeMemory(switchContext->portIdHashArray); + OvsFreeMemoryWithTag(switchContext->portIdHashArray, + OVS_SWITCH_POOL_TAG); switchContext->portIdHashArray = NULL; - OvsFreeMemory(switchContext->portNoHashArray); + OvsFreeMemoryWithTag(switchContext->portNoHashArray, + OVS_SWITCH_POOL_TAG); switchContext->portNoHashArray = NULL; - OvsFreeMemory(switchContext->pidHashArray); + OvsFreeMemoryWithTag(switchContext->pidHashArray, + OVS_SWITCH_POOL_TAG); switchContext->pidHashArray = NULL; OvsDeleteFlowTable(&switchContext->datapath); OvsCleanupBufferPool(switchContext); diff --git a/datapath-windows/ovsext/Util.h b/datapath-windows/ovsext/Util.h index 115f334f0..2cebe6f19 100644 --- a/datapath-windows/ovsext/Util.h +++ b/datapath-windows/ovsext/Util.h @@ -30,6 +30,7 @@ #define OVS_VXLAN_POOL_TAG 'XSVO' #define OVS_IPHELPER_POOL_TAG 'HSVO' #define OVS_OID_POOL_TAG 'ASVO' +#define OVS_SWITCH_POOL_TAG 'SSVO' VOID *OvsAllocateMemory(size_t size); VOID *OvsAllocateMemoryWithTag(size_t size, ULONG tag); -- cgit v1.2.1 From d016f8414d47c1fe93ba80902c1a5ee46b6fa9be Mon Sep 17 00:00:00 2001 From: Sorin Vinturis Date: Thu, 26 Mar 2015 19:59:38 +0000 Subject: datapath-windows: Added specific pool tag for user code All memory allocations within user code have 'USVO' pool tag. Signed-off-by: Sorin Vinturis Reported-by: Alin Gabriel Serdean Reported-at: https://github.com/openvswitch/ovs-issues/issues/56 Acked-by: Alin Gabriel Serdean Acked-by: Eitan Eliahu Signed-off-by: Ben Pfaff --- datapath-windows/ovsext/User.c | 18 ++++++++++-------- datapath-windows/ovsext/Util.h | 1 + 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/datapath-windows/ovsext/User.c b/datapath-windows/ovsext/User.c index d8a657e32..03f0377d9 100644 --- a/datapath-windows/ovsext/User.c +++ b/datapath-windows/ovsext/User.c @@ -85,7 +85,7 @@ OvsPurgePacketQueue(POVS_USER_PACKET_QUEUE queue, LIST_FORALL_SAFE(&tmp, link, next) { RemoveEntryList(link); elem = CONTAINING_RECORD(link, OVS_PACKET_QUEUE_ELEM, link); - OvsFreeMemory(elem); + OvsFreeMemoryWithTag(elem, OVS_USER_POOL_TAG); } } @@ -132,13 +132,13 @@ OvsCleanupPacketQueue(POVS_OPEN_INSTANCE instance) LIST_FORALL_SAFE(&tmp, link, next) { RemoveEntryList(link); elem = CONTAINING_RECORD(link, OVS_PACKET_QUEUE_ELEM, link); - OvsFreeMemory(elem); + OvsFreeMemoryWithTag(elem, OVS_USER_POOL_TAG); } if (irp) { OvsCompleteIrpRequest(irp, 0, STATUS_SUCCESS); } if (queue) { - OvsFreeMemory(queue); + OvsFreeMemoryWithTag(queue, OVS_USER_POOL_TAG); } /* Verify if gOvsSwitchContext exists. */ @@ -170,7 +170,8 @@ OvsSubscribeDpIoctl(PVOID instanceP, OvsReleasePidHashLock(); } else if (instance->packetQueue == NULL && join) { - queue = (POVS_USER_PACKET_QUEUE) OvsAllocateMemory(sizeof *queue); + queue = (POVS_USER_PACKET_QUEUE) OvsAllocateMemoryWithTag( + sizeof *queue, OVS_USER_POOL_TAG); if (queue == NULL) { return STATUS_NO_MEMORY; } @@ -248,7 +249,7 @@ OvsReadDpIoctl(PFILE_OBJECT fileObject, } *replyLen = len; - OvsFreeMemory(elem); + OvsFreeMemoryWithTag(elem, OVS_USER_POOL_TAG); } return STATUS_SUCCESS; } @@ -762,7 +763,7 @@ OvsQueuePackets(PLIST_ENTRY packetList, while (!IsListEmpty(&dropPackets)) { link = RemoveHeadList(&dropPackets); elem = CONTAINING_RECORD(link, OVS_PACKET_QUEUE_ELEM, link); - OvsFreeMemory(elem); + OvsFreeMemoryWithTag(elem, OVS_USER_POOL_TAG); num++; } @@ -1060,7 +1061,8 @@ OvsCreateQueueNlPacket(PVOID userData, dataLen + extraLen); allocLen = sizeof (OVS_PACKET_QUEUE_ELEM) + nlMsgSize; - elem = (POVS_PACKET_QUEUE_ELEM)OvsAllocateMemory(allocLen); + elem = (POVS_PACKET_QUEUE_ELEM)OvsAllocateMemoryWithTag(allocLen, + OVS_USER_POOL_TAG); if (elem == NULL) { ovsUserStats.dropDuetoResource++; return NULL; @@ -1163,6 +1165,6 @@ OvsCreateQueueNlPacket(PVOID userData, return elem; fail: - OvsFreeMemory(elem); + OvsFreeMemoryWithTag(elem, OVS_USER_POOL_TAG); return NULL; } diff --git a/datapath-windows/ovsext/Util.h b/datapath-windows/ovsext/Util.h index 2cebe6f19..a8eed9158 100644 --- a/datapath-windows/ovsext/Util.h +++ b/datapath-windows/ovsext/Util.h @@ -31,6 +31,7 @@ #define OVS_IPHELPER_POOL_TAG 'HSVO' #define OVS_OID_POOL_TAG 'ASVO' #define OVS_SWITCH_POOL_TAG 'SSVO' +#define OVS_USER_POOL_TAG 'USVO' VOID *OvsAllocateMemory(size_t size); VOID *OvsAllocateMemoryWithTag(size_t size, ULONG tag); -- cgit v1.2.1 From 2be9ec263e98138602f0a130923ef85fa6f544fd Mon Sep 17 00:00:00 2001 From: Sorin Vinturis Date: Thu, 26 Mar 2015 19:59:38 +0000 Subject: datapath-windows: Added specific pool tag for vport code All memory allocations within vport code have 'PSVO' pool tag. Signed-off-by: Sorin Vinturis Reported-by: Alin Gabriel Serdean Reported-at: https://github.com/openvswitch/ovs-issues/issues/56 Acked-by: Alin Gabriel Serdean Acked-by: Eitan Eliahu Signed-off-by: Ben Pfaff --- datapath-windows/ovsext/Util.h | 1 + datapath-windows/ovsext/Vport.c | 31 ++++++++++++++++--------------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/datapath-windows/ovsext/Util.h b/datapath-windows/ovsext/Util.h index a8eed9158..9a0124245 100644 --- a/datapath-windows/ovsext/Util.h +++ b/datapath-windows/ovsext/Util.h @@ -32,6 +32,7 @@ #define OVS_OID_POOL_TAG 'ASVO' #define OVS_SWITCH_POOL_TAG 'SSVO' #define OVS_USER_POOL_TAG 'USVO' +#define OVS_VPORT_POOL_TAG 'PSVO' VOID *OvsAllocateMemory(size_t size); VOID *OvsAllocateMemoryWithTag(size_t size, ULONG tag); diff --git a/datapath-windows/ovsext/Vport.c b/datapath-windows/ovsext/Vport.c index c9dfaeaf6..12751beaf 100644 --- a/datapath-windows/ovsext/Vport.c +++ b/datapath-windows/ovsext/Vport.c @@ -306,7 +306,7 @@ HvCreateNic(POVS_SWITCH_CONTEXT switchContext, OvsInitPhysNicVport(vport, virtExtVport, nicParam->NicIndex); status = InitHvVportCommon(switchContext, vport, TRUE); if (status != NDIS_STATUS_SUCCESS) { - OvsFreeMemory(vport); + OvsFreeMemoryWithTag(vport, OVS_VPORT_POOL_TAG); goto add_nic_done; } } @@ -658,7 +658,7 @@ OvsFindVportByHvNameA(POVS_SWITCH_CONTEXT switchContext, SIZE_T wstrSize = length * sizeof(WCHAR); UINT i; - PWSTR wsName = OvsAllocateMemory(wstrSize); + PWSTR wsName = OvsAllocateMemoryWithTag(wstrSize, OVS_VPORT_POOL_TAG); if (!wsName) { return NULL; } @@ -666,7 +666,7 @@ OvsFindVportByHvNameA(POVS_SWITCH_CONTEXT switchContext, wsName[i] = name[i]; } vport = OvsFindVportByHvNameW(switchContext, wsName, wstrSize); - OvsFreeMemory(wsName); + OvsFreeMemoryWithTag(wsName, OVS_VPORT_POOL_TAG); return vport; } @@ -703,7 +703,8 @@ POVS_VPORT_ENTRY OvsAllocateVport(VOID) { POVS_VPORT_ENTRY vport; - vport = (POVS_VPORT_ENTRY)OvsAllocateMemory(sizeof (OVS_VPORT_ENTRY)); + vport = (POVS_VPORT_ENTRY)OvsAllocateMemoryWithTag( + sizeof(OVS_VPORT_ENTRY), OVS_VPORT_POOL_TAG); if (vport == NULL) { return NULL; } @@ -1073,7 +1074,7 @@ OvsRemoveAndDeleteVport(POVS_SWITCH_CONTEXT switchContext, ASSERT(switchContext->numPhysicalNics == 0); switchContext->virtualExternalPortId = 0; switchContext->virtualExternalVport = NULL; - OvsFreeMemory(vport); + OvsFreeMemoryWithTag(vport, OVS_VPORT_POOL_TAG); if (vportDeallocated) { *vportDeallocated = TRUE; } @@ -1151,7 +1152,7 @@ OvsRemoveAndDeleteVport(POVS_SWITCH_CONTEXT switchContext, } else { switchContext->numNonHvVports--; } - OvsFreeMemory(vport); + OvsFreeMemoryWithTag(vport, OVS_VPORT_POOL_TAG); if (vportDeallocated) { *vportDeallocated = TRUE; } @@ -1189,19 +1190,20 @@ OvsAddConfiguredSwitchPorts(POVS_SWITCH_CONTEXT switchContext) OvsInitVportWithPortParam(vport, portParam); status = InitHvVportCommon(switchContext, vport, TRUE); if (status != NDIS_STATUS_SUCCESS) { - OvsFreeMemory(vport); + OvsFreeMemoryWithTag(vport, OVS_VPORT_POOL_TAG); goto cleanup; } } + cleanup: if (status != NDIS_STATUS_SUCCESS) { OvsClearAllSwitchVports(switchContext); } - if (portArray != NULL) { - OvsFreeMemory(portArray); - } + OvsFreeSwitchPortsArray(portArray); + OVS_LOG_TRACE("Exit: status: %x", status); + return status; } @@ -1248,7 +1250,7 @@ OvsInitConfiguredSwitchNics(POVS_SWITCH_CONTEXT switchContext) nicParam->NicIndex); status = InitHvVportCommon(switchContext, vport, TRUE); if (status != NDIS_STATUS_SUCCESS) { - OvsFreeMemory(vport); + OvsFreeMemoryWithTag(vport, OVS_VPORT_POOL_TAG); vport = NULL; } } @@ -1268,9 +1270,8 @@ OvsInitConfiguredSwitchNics(POVS_SWITCH_CONTEXT switchContext) } cleanup: - if (nicArray != NULL) { - OvsFreeMemory(nicArray); - } + OvsFreeSwitchNicsArray(nicArray); + OVS_LOG_TRACE("Exit: status: %x", status); return status; } @@ -2129,7 +2130,7 @@ Cleanup: OvsCleanupVxlanTunnel(vport); } } - OvsFreeMemory(vport); + OvsFreeMemoryWithTag(vport, OVS_VPORT_POOL_TAG); } NlBuildErrorMsg(msgIn, msgError, nlError); -- cgit v1.2.1 From e6d9ab56ee1f417e8823a6405d5a085c70fe8982 Mon Sep 17 00:00:00 2001 From: Jarno Rajahalme Date: Thu, 26 Mar 2015 15:32:45 -0700 Subject: flow_format: Do not format "in_port=0". flow_format() is used mainly for formating the headers of packets embedded in OpenFlow PACKET_IN messages. In this case the flow does not have a valid port number, and printing out "in_port=0" only confuses the resulting output. Besides, 0 is not a valid OpenFlow port number. Signed-off-by: Jarno Rajahalme Acked-by: Ben Pfaff --- lib/flow.c | 12 +- tests/ofp-print.at | 28 +-- tests/ofproto-dpif.at | 540 +++++++++++++++++++++++++------------------------- tests/ofproto.at | 38 ++-- 4 files changed, 311 insertions(+), 307 deletions(-) diff --git a/lib/flow.c b/lib/flow.c index aa1cc47ea..e54280a45 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -859,10 +859,14 @@ flow_format(struct ds *ds, const struct flow *flow) /* As this function is most often used for formatting a packet in a * packet-in message, skip formatting the packet context fields that are - * all-zeroes (Openflow spec encourages leaving out all-zeroes context - * fields from the packet-in messages). We make an exception with the - * 'in_port' field, which we always format, as packets usually have an - * in_port, and 0 is a port just like any other port. */ + * all-zeroes to make the print-out easier on the eyes. This means that a + * missing context field implies a zero value for that field. This is + * similar to OpenFlow encoding of these fields, as the specification + * states that all-zeroes context fields should not be encoded in the + * packet-in messages. */ + if (!flow->in_port.ofp_port) { + WC_UNMASK_FIELD(wc, in_port); + } if (!flow->skb_priority) { WC_UNMASK_FIELD(wc, skb_priority); } diff --git a/tests/ofp-print.at b/tests/ofp-print.at index 2bef3fae3..c2250d08a 100644 --- a/tests/ofp-print.at +++ b/tests/ofp-print.at @@ -447,7 +447,7 @@ c0 a8 00 02 27 2f 00 00 78 50 cc 5b 57 af 42 1e \ 50 02 02 00 26 e8 00 00 00 00 00 00 00 00 \ "], [0], [dnl OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=3 (via no_match) data_len=60 buffer=0x00000111 -tcp,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:06,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=10031,tp_dst=0,tcp_flags=syn tcp_csum:26e8 +tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:06,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=10031,tp_dst=0,tcp_flags=syn tcp_csum:26e8 ]) AT_CLEANUP @@ -461,7 +461,7 @@ c0 a8 00 02 27 2f 00 00 78 50 cc 5b 57 af 42 1e \ 50 10 02 00 26 e8 00 00 00 00 00 00 00 00 \ " 3], [0], [dnl OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=3 (via no_match) data_len=60 buffer=0x00000111 -tcp,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:06,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=10031,tp_dst=0,tcp_flags=ack tcp_csum:26e8 +tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:06,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=10031,tp_dst=0,tcp_flags=ack tcp_csum:26e8 00000000 50 54 00 00 00 06 50 54-00 00 00 05 08 00 45 00 00000010 00 28 bd 12 00 00 40 06-3c 6a c0 a8 00 01 c0 a8 00000020 00 02 27 2f 00 00 78 50-cc 5b 57 af 42 1e 50 10 @@ -480,7 +480,7 @@ c0 a8 00 02 27 2f 00 00 78 50 cc 5b 57 af 42 1e \ 50 02 02 00 26 e8 00 00 00 00 00 00 00 00 \ "], [0], [dnl OFPT_PACKET_IN (OF1.1) (xid=0x0): total_len=60 in_port=3 (via no_match) data_len=60 buffer=0x00000111 -tcp,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:06,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=10031,tp_dst=0,tcp_flags=syn tcp_csum:26e8 +tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:06,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=10031,tp_dst=0,tcp_flags=syn tcp_csum:26e8 ]) AT_CLEANUP @@ -494,7 +494,7 @@ AT_CHECK([ovs-ofctl ofp-print "\ 00 00 00 23 20 83 c1 5f 00 00 00 00 \ "], [0], [dnl OFPT_PACKET_IN (OF1.2) (xid=0x0): total_len=42 in_port=LOCAL (via no_match) data_len=42 buffer=0xffffff00 -rarp,in_port=0,vlan_tci=0x0000,dl_src=00:23:20:83:c1:5f,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=0.0.0.0,arp_tpa=0.0.0.0,arp_op=1,arp_sha=00:23:20:83:c1:5f,arp_tha=00:23:20:83:c1:5f +rarp,vlan_tci=0x0000,dl_src=00:23:20:83:c1:5f,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=0.0.0.0,arp_tpa=0.0.0.0,arp_op=1,arp_sha=00:23:20:83:c1:5f,arp_tha=00:23:20:83:c1:5f ]) AT_CLEANUP @@ -508,7 +508,7 @@ AT_CHECK([ovs-ofctl ofp-print "\ 00 00 00 23 20 83 c1 5f 00 00 00 00 \ " 3], [0], [dnl OFPT_PACKET_IN (OF1.2) (xid=0x0): total_len=42 in_port=LOCAL (via no_match) data_len=42 buffer=0xffffff00 -rarp,in_port=0,vlan_tci=0x0000,dl_src=00:23:20:83:c1:5f,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=0.0.0.0,arp_tpa=0.0.0.0,arp_op=3,arp_sha=00:23:20:83:c1:5f,arp_tha=00:23:20:83:c1:5f +rarp,vlan_tci=0x0000,dl_src=00:23:20:83:c1:5f,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=0.0.0.0,arp_tpa=0.0.0.0,arp_op=3,arp_sha=00:23:20:83:c1:5f,arp_tha=00:23:20:83:c1:5f 00000000 ff ff ff ff ff ff 00 23-20 83 c1 5f 80 35 00 01 00000010 08 00 06 04 00 03 00 23-20 83 c1 5f 00 00 00 00 00000020 00 23 20 83 c1 5f 00 00-00 00 @@ -526,7 +526,7 @@ ff ff ff fe 00 00 00 00 00 00 ff ff ff ff ff ff \ 00 00 00 00 \ "], [0], [dnl OFPT_PACKET_IN (OF1.3) (xid=0x0): cookie=0x102030405060708 total_len=42 in_port=LOCAL (via no_match) data_len=42 buffer=0xffffff00 -rarp,in_port=0,vlan_tci=0x0000,dl_src=00:23:20:83:c1:5f,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=0.0.0.0,arp_tpa=0.0.0.0,arp_op=3,arp_sha=00:23:20:83:c1:5f,arp_tha=00:23:20:83:c1:5f +rarp,vlan_tci=0x0000,dl_src=00:23:20:83:c1:5f,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=0.0.0.0,arp_tpa=0.0.0.0,arp_op=3,arp_sha=00:23:20:83:c1:5f,arp_tha=00:23:20:83:c1:5f ]) AT_CLEANUP @@ -541,7 +541,7 @@ ff ff ff fe 00 00 00 00 00 00 ff ff ff ff ff ff \ 00 00 00 00 \ "], [0], [dnl OFPT_PACKET_IN (OF1.4) (xid=0x0): cookie=0x102030405060708 total_len=42 in_port=LOCAL (via no_match) data_len=42 buffer=0xffffff00 -rarp,in_port=0,vlan_tci=0x0000,dl_src=00:23:20:83:c1:5f,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=0.0.0.0,arp_tpa=0.0.0.0,arp_op=3,arp_sha=00:23:20:83:c1:5f,arp_tha=00:23:20:83:c1:5f +rarp,vlan_tci=0x0000,dl_src=00:23:20:83:c1:5f,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=0.0.0.0,arp_tpa=0.0.0.0,arp_op=3,arp_sha=00:23:20:83:c1:5f,arp_tha=00:23:20:83:c1:5f ]) AT_CLEANUP @@ -556,7 +556,7 @@ ff ff ff fe 00 00 00 00 00 00 ff ff ff ff ff ff \ 00 00 00 00 \ "], [0], [dnl OFPT_PACKET_IN (OF1.5) (xid=0x0): cookie=0x102030405060708 total_len=42 in_port=LOCAL (via no_match) data_len=42 buffer=0xffffff00 -rarp,in_port=0,vlan_tci=0x0000,dl_src=00:23:20:83:c1:5f,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=0.0.0.0,arp_tpa=0.0.0.0,arp_op=3,arp_sha=00:23:20:83:c1:5f,arp_tha=00:23:20:83:c1:5f +rarp,vlan_tci=0x0000,dl_src=00:23:20:83:c1:5f,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=0.0.0.0,arp_tpa=0.0.0.0,arp_op=3,arp_sha=00:23:20:83:c1:5f,arp_tha=00:23:20:83:c1:5f ]) AT_CLEANUP @@ -571,7 +571,7 @@ ff ff ff fe 00 00 00 00 00 00 ff ff ff ff ff ff \ 00 00 00 00 \ " 3], [0], [dnl OFPT_PACKET_IN (OF1.3) (xid=0x0): cookie=0x102030405060708 total_len=42 in_port=LOCAL (via no_match) data_len=42 buffer=0xffffff00 -rarp,in_port=0,vlan_tci=0x0000,dl_src=00:23:20:83:c1:5f,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=0.0.0.0,arp_tpa=0.0.0.0,arp_op=3,arp_sha=00:23:20:83:c1:5f,arp_tha=00:23:20:83:c1:5f +rarp,vlan_tci=0x0000,dl_src=00:23:20:83:c1:5f,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=0.0.0.0,arp_tpa=0.0.0.0,arp_op=3,arp_sha=00:23:20:83:c1:5f,arp_tha=00:23:20:83:c1:5f 00000000 ff ff ff ff ff ff 00 23-20 83 c1 5f 80 35 00 01 00000010 08 00 06 04 00 03 00 23-20 83 c1 5f 00 00 00 00 00000020 00 23 20 83 c1 5f 00 00-00 00 @@ -696,7 +696,7 @@ b9 7c c0 a8 00 02 c0 a8 00 01 00 00 2b 60 00 00 \ 00 00 00 00 \ "], [0], [dnl OFPT_PACKET_OUT (xid=0x0): in_port=1 actions=output:3 data_len=60 -tcp,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,nw_src=192.168.0.2,nw_dst=192.168.0.1,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=11104,tcp_flags=rst|ack tcp_csum:6d75 +tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,nw_src=192.168.0.2,nw_dst=192.168.0.1,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=11104,tcp_flags=rst|ack tcp_csum:6d75 ]) AT_CLEANUP @@ -711,7 +711,7 @@ b9 7c c0 a8 00 02 c0 a8 00 01 00 00 2b 60 00 00 \ 00 00 00 00 \ " 3], [0], [dnl OFPT_PACKET_OUT (xid=0x0): in_port=1 actions=output:3 data_len=60 -tcp,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,nw_src=192.168.0.2,nw_dst=192.168.0.1,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=11104,tcp_flags=rst|ack tcp_csum:6d75 +tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,nw_src=192.168.0.2,nw_dst=192.168.0.1,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=11104,tcp_flags=rst|ack tcp_csum:6d75 00000000 50 54 00 00 00 05 50 54-00 00 00 06 08 00 45 00 00000010 00 28 00 00 40 00 40 06-b9 7c c0 a8 00 02 c0 a8 00000020 00 01 00 00 2b 60 00 00-00 00 6a 4f 2b 58 50 14 @@ -742,7 +742,7 @@ b9 7c c0 a8 00 02 c0 a8 00 01 00 00 2b 60 00 00 \ 00 00 00 00 \ "], [0], [dnl OFPT_PACKET_OUT (OF1.2) (xid=0x8858dfc5): in_port=LOCAL actions=FLOOD data_len=60 -tcp,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,nw_src=192.168.0.2,nw_dst=192.168.0.1,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=11104,tcp_flags=rst|ack tcp_csum:6d75 +tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,nw_src=192.168.0.2,nw_dst=192.168.0.1,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=11104,tcp_flags=rst|ack tcp_csum:6d75 ]) AT_CLEANUP @@ -2703,7 +2703,7 @@ ff ff ff ff ff ff 00 00 00 00 82 82 82 82 82 82 \ 31 6d 00 00 00 00 00 00 00 00 \ "], [0], [dnl NXT_PACKET_IN (xid=0x0): table_id=7 cookie=0x9 total_len=64 in_port=1 tun_id=0x6 metadata=0x5a5a5a5a5a5a5a5a reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered) -tcp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=85,tp_dst=86,tcp_flags=syn tcp_csum:316d +tcp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=85,tp_dst=86,tcp_flags=syn tcp_csum:316d ]) AT_CLEANUP @@ -2724,7 +2724,7 @@ ff ff ff ff ff ff 00 00 00 00 82 82 82 82 82 82 \ 31 6d 00 00 00 00 00 00 00 00 \ " 3], [0], [dnl NXT_PACKET_IN (xid=0x0): table_id=7 cookie=0x9 total_len=64 in_port=1 tun_id=0x6 metadata=0x5a5a5a5a5a5a5a5a reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered) -tcp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=85,tp_dst=86,tcp_flags=fin tcp_csum:316d +tcp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=85,tp_dst=86,tcp_flags=fin tcp_csum:316d 00000000 82 82 82 82 82 82 80 81-81 81 81 81 81 00 00 50 00000010 08 00 45 00 00 28 00 00-00 00 00 06 32 05 53 53 00000020 53 53 54 54 54 54 00 55-00 56 00 00 00 00 00 00 diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at index f3d886f1a..89ba11222 100644 --- a/tests/ofproto-dpif.at +++ b/tests/ofproto-dpif.at @@ -725,7 +725,7 @@ AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=50:54:00:00:00: OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit]) AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x0 total_len=34 in_port=1 (via invalid_ttl) data_len=34 (unbuffered) -ip,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=111,nw_tos=0,nw_ecn=0,nw_ttl=1 +ip,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=111,nw_tos=0,nw_ecn=0,nw_ttl=1 ]) OVS_VSWITCHD_STOP AT_CLEANUP @@ -901,13 +901,13 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6]) OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit]) AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=syn tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=syn tcp_csum:0 dnl NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=syn tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=syn tcp_csum:0 dnl NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=syn tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=syn tcp_csum:0 ]) AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore]) @@ -964,13 +964,13 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6]) OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit]) AT_CHECK([cat ofctl_monitor.log], [0], [dnl OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=rst|urg tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=rst|urg tcp_csum:0 dnl OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=rst|urg tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=rst|urg tcp_csum:0 dnl OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=rst|urg tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=rst|urg tcp_csum:0 ]) AT_CHECK([ovs-appctl revalidator/purge], [0]) @@ -1031,13 +1031,13 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit]) AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0 dnl NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0 dnl NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0 ]) dnl Hit table 0, Miss all other tables, sent to controller @@ -1051,13 +1051,13 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit]) AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): table_id=253 cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0 dnl NXT_PACKET_IN (xid=0x0): table_id=253 cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0 dnl NXT_PACKET_IN (xid=0x0): table_id=253 cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0 ]) AT_CHECK([ovs-appctl revalidator/purge], [0]) @@ -1094,13 +1094,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): table_id=2 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0 dnl NXT_PACKET_IN (xid=0x0): table_id=2 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0 dnl NXT_PACKET_IN (xid=0x0): table_id=2 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0 ]) dnl Hit table 1, Miss all other tables, sent to controller @@ -1114,13 +1114,13 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit]) AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): table_id=253 cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0 dnl NXT_PACKET_IN (xid=0x0): table_id=253 cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0 dnl NXT_PACKET_IN (xid=0x0): table_id=253 cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0 ]) AT_CHECK([ovs-appctl revalidator/purge], [0]) @@ -1304,13 +1304,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log], [0], [dnl OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0 dnl OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0 dnl OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0 ]) dnl Singleton controller action. @@ -1324,13 +1324,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log], [0], [dnl OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 dnl OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 dnl OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 ]) dnl Modified controller action. @@ -1344,13 +1344,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log], [0], [dnl OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -tcp,in_port=0,dl_vlan=15,dl_vlan_pcp=0,dl_src=30:33:33:33:33:33,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=fin tcp_csum:0 +tcp,dl_vlan=15,dl_vlan_pcp=0,dl_src=30:33:33:33:33:33,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=fin tcp_csum:0 dnl OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -tcp,in_port=0,dl_vlan=15,dl_vlan_pcp=0,dl_src=30:33:33:33:33:33,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=fin tcp_csum:0 +tcp,dl_vlan=15,dl_vlan_pcp=0,dl_src=30:33:33:33:33:33,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=fin tcp_csum:0 dnl OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -tcp,in_port=0,dl_vlan=15,dl_vlan_pcp=0,dl_src=30:33:33:33:33:33,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=fin tcp_csum:0 +tcp,dl_vlan=15,dl_vlan_pcp=0,dl_src=30:33:33:33:33:33,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=fin tcp_csum:0 ]) dnl Modified VLAN controller action. @@ -1364,13 +1364,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -ip,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:44:41,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=16,nw_tos=0,nw_ecn=0,nw_ttl=64 +ip,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:44:41,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=16,nw_tos=0,nw_ecn=0,nw_ttl=64 dnl NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -ip,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:44:41,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=16,nw_tos=0,nw_ecn=0,nw_ttl=64 +ip,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:44:41,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=16,nw_tos=0,nw_ecn=0,nw_ttl=64 dnl NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -ip,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:44:41,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=16,nw_tos=0,nw_ecn=0,nw_ttl=64 +ip,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:44:41,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=16,nw_tos=0,nw_ecn=0,nw_ttl=64 ]) dnl Checksum TCP. @@ -1384,31 +1384,31 @@ ovs-appctl -t ovs-ofctl exit AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0x1 total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=20:22:22:22:22:22,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=11,tcp_flags=fin tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=20:22:22:22:22:22,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=11,tcp_flags=fin tcp_csum:0 dnl NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x3 total_len=64 in_port=1 reg0=0x1 (via action) data_len=64 (unbuffered) -tcp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=20:22:22:22:22:22,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=11,tcp_flags=fin tcp_csum:0 +tcp,dl_vlan=80,dl_vlan_pcp=0,dl_src=20:22:22:22:22:22,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=11,tcp_flags=fin tcp_csum:0 dnl NXT_PACKET_IN (xid=0x0): table_id=2 cookie=0x4 total_len=64 in_port=1 reg0=0x1 reg1=0x2 (via action) data_len=64 (unbuffered) -tcp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=11,tcp_flags=fin tcp_csum:0 +tcp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=11,tcp_flags=fin tcp_csum:0 dnl NXT_PACKET_IN (xid=0x0): table_id=3 cookie=0x5 total_len=64 in_port=1 reg0=0x1 reg1=0x2 reg2=0x3 (via action) data_len=64 (unbuffered) -tcp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=11,tcp_flags=fin tcp_csum:0 +tcp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=11,tcp_flags=fin tcp_csum:0 dnl NXT_PACKET_IN (xid=0x0): table_id=4 cookie=0x6 total_len=64 in_port=1 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 (via action) data_len=64 (unbuffered) -tcp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=11,tcp_flags=fin tcp_csum:1a03 +tcp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=11,tcp_flags=fin tcp_csum:1a03 dnl NXT_PACKET_IN (xid=0x0): table_id=5 cookie=0x7 total_len=64 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered) -tcp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=11,tcp_flags=fin tcp_csum:3205 +tcp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=11,tcp_flags=fin tcp_csum:3205 dnl NXT_PACKET_IN (xid=0x0): table_id=6 cookie=0x8 total_len=64 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered) -tcp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=85,tp_dst=11,tcp_flags=fin tcp_csum:31b8 +tcp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=85,tp_dst=11,tcp_flags=fin tcp_csum:31b8 dnl NXT_PACKET_IN (xid=0x0): table_id=7 cookie=0x9 total_len=64 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered) -tcp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=85,tp_dst=86,tcp_flags=fin tcp_csum:316d +tcp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=85,tp_dst=86,tcp_flags=fin tcp_csum:316d dnl NXT_PACKET_IN (xid=0x0): table_id=7 cookie=0x9 total_len=64 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered) -tcp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=85,tp_dst=86,tcp_flags=fin tcp_csum:316d +tcp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=85,tp_dst=86,tcp_flags=fin tcp_csum:316d ]) dnl Checksum UDP. @@ -1422,31 +1422,31 @@ ovs-appctl -t ovs-ofctl exit AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0x1 total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -udp,in_port=0,vlan_tci=0x0000,dl_src=20:22:22:22:22:22,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=11 udp_csum:1234 +udp,vlan_tci=0x0000,dl_src=20:22:22:22:22:22,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=11 udp_csum:1234 dnl NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x3 total_len=64 in_port=1 reg0=0x1 (via action) data_len=64 (unbuffered) -udp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=20:22:22:22:22:22,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=11 udp_csum:1234 +udp,dl_vlan=80,dl_vlan_pcp=0,dl_src=20:22:22:22:22:22,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=11 udp_csum:1234 dnl NXT_PACKET_IN (xid=0x0): table_id=2 cookie=0x4 total_len=64 in_port=1 reg0=0x1 reg1=0x2 (via action) data_len=64 (unbuffered) -udp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=11 udp_csum:1234 +udp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=11 udp_csum:1234 dnl NXT_PACKET_IN (xid=0x0): table_id=3 cookie=0x5 total_len=64 in_port=1 reg0=0x1 reg1=0x2 reg2=0x3 (via action) data_len=64 (unbuffered) -udp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=11 udp_csum:1234 +udp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=11 udp_csum:1234 dnl NXT_PACKET_IN (xid=0x0): table_id=4 cookie=0x6 total_len=64 in_port=1 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 (via action) data_len=64 (unbuffered) -udp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=11 udp_csum:2c37 +udp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=11 udp_csum:2c37 dnl NXT_PACKET_IN (xid=0x0): table_id=5 cookie=0x7 total_len=64 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered) -udp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=11 udp_csum:4439 +udp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=11 udp_csum:4439 dnl NXT_PACKET_IN (xid=0x0): table_id=6 cookie=0x8 total_len=64 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered) -udp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=85,tp_dst=11 udp_csum:43ec +udp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=85,tp_dst=11 udp_csum:43ec dnl NXT_PACKET_IN (xid=0x0): table_id=7 cookie=0x9 total_len=64 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered) -udp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=85,tp_dst=86 udp_csum:43a1 +udp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=85,tp_dst=86 udp_csum:43a1 dnl NXT_PACKET_IN (xid=0x0): table_id=7 cookie=0x9 total_len=64 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered) -udp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=85,tp_dst=86 udp_csum:43a1 +udp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=85,tp_dst=86 udp_csum:43a1 ]) dnl Modified ARP controller action. @@ -1460,23 +1460,23 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 18]) OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit]) AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -arp,in_port=0,vlan_tci=0x0000,dl_src=80:88:88:88:88:88,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=192.168.0.1,arp_tpa=192.168.0.2,arp_op=2,arp_sha=50:54:00:00:00:05,arp_tha=00:00:00:00:00:00 +arp,vlan_tci=0x0000,dl_src=80:88:88:88:88:88,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=192.168.0.1,arp_tpa=192.168.0.2,arp_op=2,arp_sha=50:54:00:00:00:05,arp_tha=00:00:00:00:00:00 NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -arp,in_port=0,vlan_tci=0x0000,dl_src=80:88:88:88:88:88,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=192.168.128.1,arp_tpa=192.168.0.2,arp_op=2,arp_sha=50:54:00:00:00:05,arp_tha=00:00:00:00:00:00 +arp,vlan_tci=0x0000,dl_src=80:88:88:88:88:88,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=192.168.128.1,arp_tpa=192.168.0.2,arp_op=2,arp_sha=50:54:00:00:00:05,arp_tha=00:00:00:00:00:00 NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -arp,in_port=0,vlan_tci=0x0000,dl_src=80:88:88:88:88:88,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=1.1.1.1,arp_tpa=2.2.2.2,arp_op=2,arp_sha=50:54:00:00:00:05,arp_tha=40:44:44:44:44:41 +arp,vlan_tci=0x0000,dl_src=80:88:88:88:88:88,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=1.1.1.1,arp_tpa=2.2.2.2,arp_op=2,arp_sha=50:54:00:00:00:05,arp_tha=40:44:44:44:44:41 NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -arp,in_port=0,vlan_tci=0x0000,dl_src=80:88:88:88:88:88,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=192.168.0.1,arp_tpa=192.168.0.2,arp_op=2,arp_sha=50:54:00:00:00:05,arp_tha=00:00:00:00:00:00 +arp,vlan_tci=0x0000,dl_src=80:88:88:88:88:88,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=192.168.0.1,arp_tpa=192.168.0.2,arp_op=2,arp_sha=50:54:00:00:00:05,arp_tha=00:00:00:00:00:00 NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -arp,in_port=0,vlan_tci=0x0000,dl_src=80:88:88:88:88:88,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=192.168.128.1,arp_tpa=192.168.0.2,arp_op=2,arp_sha=50:54:00:00:00:05,arp_tha=00:00:00:00:00:00 +arp,vlan_tci=0x0000,dl_src=80:88:88:88:88:88,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=192.168.128.1,arp_tpa=192.168.0.2,arp_op=2,arp_sha=50:54:00:00:00:05,arp_tha=00:00:00:00:00:00 NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -arp,in_port=0,vlan_tci=0x0000,dl_src=80:88:88:88:88:88,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=1.1.1.1,arp_tpa=2.2.2.2,arp_op=2,arp_sha=50:54:00:00:00:05,arp_tha=40:44:44:44:44:41 +arp,vlan_tci=0x0000,dl_src=80:88:88:88:88:88,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=1.1.1.1,arp_tpa=2.2.2.2,arp_op=2,arp_sha=50:54:00:00:00:05,arp_tha=40:44:44:44:44:41 NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -arp,in_port=0,vlan_tci=0x0000,dl_src=80:88:88:88:88:88,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=192.168.0.1,arp_tpa=192.168.0.2,arp_op=2,arp_sha=50:54:00:00:00:05,arp_tha=00:00:00:00:00:00 +arp,vlan_tci=0x0000,dl_src=80:88:88:88:88:88,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=192.168.0.1,arp_tpa=192.168.0.2,arp_op=2,arp_sha=50:54:00:00:00:05,arp_tha=00:00:00:00:00:00 NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -arp,in_port=0,vlan_tci=0x0000,dl_src=80:88:88:88:88:88,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=192.168.128.1,arp_tpa=192.168.0.2,arp_op=2,arp_sha=50:54:00:00:00:05,arp_tha=00:00:00:00:00:00 +arp,vlan_tci=0x0000,dl_src=80:88:88:88:88:88,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=192.168.128.1,arp_tpa=192.168.0.2,arp_op=2,arp_sha=50:54:00:00:00:05,arp_tha=00:00:00:00:00:00 NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -arp,in_port=0,vlan_tci=0x0000,dl_src=80:88:88:88:88:88,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=1.1.1.1,arp_tpa=2.2.2.2,arp_op=2,arp_sha=50:54:00:00:00:05,arp_tha=40:44:44:44:44:41 +arp,vlan_tci=0x0000,dl_src=80:88:88:88:88:88,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=1.1.1.1,arp_tpa=2.2.2.2,arp_op=2,arp_sha=50:54:00:00:00:05,arp_tha=40:44:44:44:44:41 ]) AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore]) @@ -1493,31 +1493,31 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 18]) OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit]) AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0x1 total_len=98 in_port=1 (via action) data_len=98 (unbuffered) -sctp,in_port=0,vlan_tci=0x0000,dl_src=20:22:22:22:22:22,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=1112,tp_dst=2223 sctp_csum:d9d79157 +sctp,vlan_tci=0x0000,dl_src=20:22:22:22:22:22,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=1112,tp_dst=2223 sctp_csum:d9d79157 dnl NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x3 total_len=102 in_port=1 reg0=0x1 (via action) data_len=102 (unbuffered) -sctp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=20:22:22:22:22:22,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=1112,tp_dst=2223 sctp_csum:d9d79157 +sctp,dl_vlan=80,dl_vlan_pcp=0,dl_src=20:22:22:22:22:22,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=1112,tp_dst=2223 sctp_csum:d9d79157 dnl NXT_PACKET_IN (xid=0x0): table_id=2 cookie=0x4 total_len=102 in_port=1 reg0=0x1 reg1=0x2 (via action) data_len=102 (unbuffered) -sctp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=1112,tp_dst=2223 sctp_csum:d9d79157 +sctp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=1112,tp_dst=2223 sctp_csum:d9d79157 dnl NXT_PACKET_IN (xid=0x0): table_id=3 cookie=0x5 total_len=102 in_port=1 reg0=0x1 reg1=0x2 reg2=0x3 (via action) data_len=102 (unbuffered) -sctp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=1112,tp_dst=2223 sctp_csum:d9d79157 +sctp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=1112,tp_dst=2223 sctp_csum:d9d79157 dnl NXT_PACKET_IN (xid=0x0): table_id=4 cookie=0x6 total_len=102 in_port=1 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 (via action) data_len=102 (unbuffered) -sctp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=1112,tp_dst=2223 sctp_csum:d9d79157 +sctp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=1112,tp_dst=2223 sctp_csum:d9d79157 dnl NXT_PACKET_IN (xid=0x0): table_id=5 cookie=0x7 total_len=102 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=102 (unbuffered) -sctp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=1112,tp_dst=2223 sctp_csum:d9d79157 +sctp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=1112,tp_dst=2223 sctp_csum:d9d79157 dnl NXT_PACKET_IN (xid=0x0): table_id=6 cookie=0x8 total_len=102 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=102 (unbuffered) -sctp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=85,tp_dst=2223 sctp_csum:dd778f5f +sctp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=85,tp_dst=2223 sctp_csum:dd778f5f dnl NXT_PACKET_IN (xid=0x0): table_id=7 cookie=0x9 total_len=102 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=102 (unbuffered) -sctp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=85,tp_dst=86 sctp_csum:62051f56 +sctp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=85,tp_dst=86 sctp_csum:62051f56 dnl NXT_PACKET_IN (xid=0x0): table_id=7 cookie=0x9 total_len=102 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=102 (unbuffered) -sctp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=85,tp_dst=86 sctp_csum:62051f56 +sctp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=85,tp_dst=86 sctp_csum:62051f56 ]) AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl @@ -1609,13 +1609,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:42,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=1 +mpls,vlan_tci=0x0000,dl_src=40:44:44:44:44:42,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=1 dnl NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:42,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=1 +mpls,vlan_tci=0x0000,dl_src=40:44:44:44:44:42,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=1 dnl NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:42,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=1 +mpls,vlan_tci=0x0000,dl_src=40:44:44:44:44:42,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=1 ]) dnl Modified MPLS controller action. @@ -1629,13 +1629,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -ip,in_port=0,vlan_tci=0x0000,dl_src=41:44:44:44:44:42,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=16,nw_tos=0,nw_ecn=0,nw_ttl=64 +ip,vlan_tci=0x0000,dl_src=41:44:44:44:44:42,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=16,nw_tos=0,nw_ecn=0,nw_ttl=64 dnl NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -ip,in_port=0,vlan_tci=0x0000,dl_src=41:44:44:44:44:42,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=16,nw_tos=0,nw_ecn=0,nw_ttl=64 +ip,vlan_tci=0x0000,dl_src=41:44:44:44:44:42,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=16,nw_tos=0,nw_ecn=0,nw_ttl=64 dnl NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -ip,in_port=0,vlan_tci=0x0000,dl_src=41:44:44:44:44:42,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=16,nw_tos=0,nw_ecn=0,nw_ttl=64 +ip,vlan_tci=0x0000,dl_src=41:44:44:44:44:42,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=16,nw_tos=0,nw_ecn=0,nw_ttl=64 ]) dnl Modified MPLS controller action. @@ -1651,13 +1651,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:43,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=0,mpls_lse1=46912 +mpls,vlan_tci=0x0000,dl_src=40:44:44:44:44:43,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=0,mpls_lse1=46912 dnl NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:43,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=0,mpls_lse1=46912 +mpls,vlan_tci=0x0000,dl_src=40:44:44:44:44:43,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=0,mpls_lse1=46912 dnl NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:43,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=0,mpls_lse1=46912 +mpls,vlan_tci=0x0000,dl_src=40:44:44:44:44:43,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=0,mpls_lse1=46912 ]) dnl Modified MPLS controller action. @@ -1671,13 +1671,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=7,dl_src=40:44:44:44:44:44,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=1 +mpls,dl_vlan=99,dl_vlan_pcp=7,dl_src=40:44:44:44:44:44,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=1 dnl NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=7,dl_src=40:44:44:44:44:44,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=1 +mpls,dl_vlan=99,dl_vlan_pcp=7,dl_src=40:44:44:44:44:44,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=1 dnl NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=7,dl_src=40:44:44:44:44:44,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=1 +mpls,dl_vlan=99,dl_vlan_pcp=7,dl_src=40:44:44:44:44:44,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=1 ]) dnl Modified MPLS controller action. @@ -1691,13 +1691,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:45,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=63,mpls_bos=1 +mpls,vlan_tci=0x0000,dl_src=40:44:44:44:44:45,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=63,mpls_bos=1 dnl NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:45,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=63,mpls_bos=1 +mpls,vlan_tci=0x0000,dl_src=40:44:44:44:44:45,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=63,mpls_bos=1 dnl NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:45,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=63,mpls_bos=1 +mpls,vlan_tci=0x0000,dl_src=40:44:44:44:44:45,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=63,mpls_bos=1 ]) dnl Modified MPLS controller action. @@ -1711,13 +1711,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:46,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=10,mpls_bos=1 +mpls,vlan_tci=0x0000,dl_src=40:44:44:44:44:46,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=10,mpls_bos=1 dnl NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:46,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=10,mpls_bos=1 +mpls,vlan_tci=0x0000,dl_src=40:44:44:44:44:46,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=10,mpls_bos=1 dnl NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:46,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=10,mpls_bos=1 +mpls,vlan_tci=0x0000,dl_src=40:44:44:44:44:46,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=10,mpls_bos=1 ]) dnl Modified MPLS controller action. @@ -1731,13 +1731,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:47,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=10,mpls_bos=1 +mpls,vlan_tci=0x0000,dl_src=40:44:44:44:44:47,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=10,mpls_bos=1 dnl NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:47,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=10,mpls_bos=1 +mpls,vlan_tci=0x0000,dl_src=40:44:44:44:44:47,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=10,mpls_bos=1 dnl NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:47,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=10,mpls_bos=1 +mpls,vlan_tci=0x0000,dl_src=40:44:44:44:44:47,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=10,mpls_bos=1 ]) AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore]) @@ -1753,13 +1753,13 @@ ovs-appctl -t ovs-ofctl exit AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mplsm,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:49,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=0,mpls_lse1=42816 +mplsm,vlan_tci=0x0000,dl_src=40:44:44:44:44:49,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=0,mpls_lse1=42816 dnl NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mplsm,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:49,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=0,mpls_lse1=42816 +mplsm,vlan_tci=0x0000,dl_src=40:44:44:44:44:49,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=0,mpls_lse1=42816 dnl NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mplsm,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:49,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=0,mpls_lse1=42816 +mplsm,vlan_tci=0x0000,dl_src=40:44:44:44:44:49,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=0,mpls_lse1=42816 ]) AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore]) @@ -1775,13 +1775,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:48,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=9,mpls_bos=1 +mpls,vlan_tci=0x0000,dl_src=40:44:44:44:44:48,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=9,mpls_bos=1 dnl NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:48,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=9,mpls_bos=1 +mpls,vlan_tci=0x0000,dl_src=40:44:44:44:44:48,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=9,mpls_bos=1 dnl NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:48,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=9,mpls_bos=1 +mpls,vlan_tci=0x0000,dl_src=40:44:44:44:44:48,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=9,mpls_bos=1 ]) dnl Modified MPLS actions. @@ -1795,13 +1795,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0xb total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -mpls,in_port=0,vlan_tci=0x0000,dl_src=50:55:55:55:55:55,dl_dst=50:54:00:00:00:07,mpls_label=1000,mpls_tc=7,mpls_ttl=64,mpls_bos=1 +mpls,vlan_tci=0x0000,dl_src=50:55:55:55:55:55,dl_dst=50:54:00:00:00:07,mpls_label=1000,mpls_tc=7,mpls_ttl=64,mpls_bos=1 dnl NXT_PACKET_IN (xid=0x0): cookie=0xb total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -mpls,in_port=0,vlan_tci=0x0000,dl_src=50:55:55:55:55:55,dl_dst=50:54:00:00:00:07,mpls_label=1000,mpls_tc=7,mpls_ttl=64,mpls_bos=1 +mpls,vlan_tci=0x0000,dl_src=50:55:55:55:55:55,dl_dst=50:54:00:00:00:07,mpls_label=1000,mpls_tc=7,mpls_ttl=64,mpls_bos=1 dnl NXT_PACKET_IN (xid=0x0): cookie=0xb total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -mpls,in_port=0,vlan_tci=0x0000,dl_src=50:55:55:55:55:55,dl_dst=50:54:00:00:00:07,mpls_label=1000,mpls_tc=7,mpls_ttl=64,mpls_bos=1 +mpls,vlan_tci=0x0000,dl_src=50:55:55:55:55:55,dl_dst=50:54:00:00:00:07,mpls_label=1000,mpls_tc=7,mpls_ttl=64,mpls_bos=1 ]) dnl Modified MPLS ipv6 controller action. @@ -1815,13 +1815,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0xc total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mplsm,in_port=0,vlan_tci=0x0000,dl_src=70:77:77:77:77:77,dl_dst=50:54:00:00:00:07,mpls_label=1000,mpls_tc=7,mpls_ttl=128,mpls_bos=1 +mplsm,vlan_tci=0x0000,dl_src=70:77:77:77:77:77,dl_dst=50:54:00:00:00:07,mpls_label=1000,mpls_tc=7,mpls_ttl=128,mpls_bos=1 dnl NXT_PACKET_IN (xid=0x0): cookie=0xc total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mplsm,in_port=0,vlan_tci=0x0000,dl_src=70:77:77:77:77:77,dl_dst=50:54:00:00:00:07,mpls_label=1000,mpls_tc=7,mpls_ttl=128,mpls_bos=1 +mplsm,vlan_tci=0x0000,dl_src=70:77:77:77:77:77,dl_dst=50:54:00:00:00:07,mpls_label=1000,mpls_tc=7,mpls_ttl=128,mpls_bos=1 dnl NXT_PACKET_IN (xid=0x0): cookie=0xc total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mplsm,in_port=0,vlan_tci=0x0000,dl_src=70:77:77:77:77:77,dl_dst=50:54:00:00:00:07,mpls_label=1000,mpls_tc=7,mpls_ttl=128,mpls_bos=1 +mplsm,vlan_tci=0x0000,dl_src=70:77:77:77:77:77,dl_dst=50:54:00:00:00:07,mpls_label=1000,mpls_tc=7,mpls_ttl=128,mpls_bos=1 ]) @@ -1843,13 +1843,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:66:66,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:66:66,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:66:66,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:66:66,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:66:66,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:66:66,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 ]) AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore]) @@ -1869,13 +1869,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:01,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:01,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:01,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:01,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:01,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:01,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 ]) AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore]) @@ -1895,13 +1895,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:02,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=10.0.0.1,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2dee +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:02,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=10.0.0.1,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2dee dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:02,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=10.0.0.1,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2dee +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:02,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=10.0.0.1,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2dee dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:02,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=10.0.0.1,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2dee +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:02,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=10.0.0.1,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2dee ]) AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore]) @@ -1921,13 +1921,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:03,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.2,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7743 +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:03,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.2,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7743 dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:03,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.2,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7743 +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:03,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.2,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7743 dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:03,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.2,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7743 +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:03,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.2,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7743 ]) AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore]) @@ -1947,13 +1947,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:04,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.2,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7743 +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:04,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.2,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7743 dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:04,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.2,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7743 +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:04,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.2,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7743 dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:04,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.2,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7743 +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:04,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.2,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7743 ]) AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore]) @@ -1973,13 +1973,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.106,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:76db +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.106,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:76db dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.106,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:76db +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.106,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:76db dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.106,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:76db +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.106,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:76db ]) AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore]) @@ -1999,13 +1999,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:06,dl_dst=50:54:00:00:00:07,nw_src=192.168.255.255,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7745 +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:06,dl_dst=50:54:00:00:00:07,nw_src=192.168.255.255,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7745 dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:06,dl_dst=50:54:00:00:00:07,nw_src=192.168.255.255,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7745 +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:06,dl_dst=50:54:00:00:00:07,nw_src=192.168.255.255,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7745 dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:06,dl_dst=50:54:00:00:00:07,nw_src=192.168.255.255,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7745 +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:06,dl_dst=50:54:00:00:00:07,nw_src=192.168.255.255,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7745 ]) AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore]) @@ -2025,13 +2025,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:07,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:07,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:07,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:07,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:07,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:07,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 ]) AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore]) @@ -2049,13 +2049,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0xd total_len=56 in_port=1 (via action) data_len=56 (unbuffered) -arp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:08,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=192.168.0.1,arp_tpa=255.255.255.255,arp_op=2,arp_sha=60:66:66:66:00:08,arp_tha=ff:ff:ff:ff:ff:ff +arp,vlan_tci=0x0000,dl_src=60:66:66:66:00:08,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=192.168.0.1,arp_tpa=255.255.255.255,arp_op=2,arp_sha=60:66:66:66:00:08,arp_tha=ff:ff:ff:ff:ff:ff dnl NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0xd total_len=56 in_port=1 (via action) data_len=56 (unbuffered) -arp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:08,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=192.168.0.1,arp_tpa=255.255.255.255,arp_op=2,arp_sha=60:66:66:66:00:08,arp_tha=ff:ff:ff:ff:ff:ff +arp,vlan_tci=0x0000,dl_src=60:66:66:66:00:08,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=192.168.0.1,arp_tpa=255.255.255.255,arp_op=2,arp_sha=60:66:66:66:00:08,arp_tha=ff:ff:ff:ff:ff:ff dnl NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0xd total_len=56 in_port=1 (via action) data_len=56 (unbuffered) -arp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:08,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=192.168.0.1,arp_tpa=255.255.255.255,arp_op=2,arp_sha=60:66:66:66:00:08,arp_tha=ff:ff:ff:ff:ff:ff +arp,vlan_tci=0x0000,dl_src=60:66:66:66:00:08,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=192.168.0.1,arp_tpa=255.255.255.255,arp_op=2,arp_sha=60:66:66:66:00:08,arp_tha=ff:ff:ff:ff:ff:ff ]) AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore]) @@ -2075,13 +2075,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:09,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=48,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:09,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=48,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:09,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=48,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:09,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=48,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:09,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=48,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:09,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=48,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 ]) AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore]) @@ -2101,13 +2101,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:0a,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=10.0.0.1,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2dee +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:0a,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=10.0.0.1,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2dee dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:0a,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=10.0.0.1,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2dee +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:0a,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=10.0.0.1,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2dee dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:0a,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=10.0.0.1,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2dee +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:0a,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=10.0.0.1,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2dee ]) AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore]) @@ -2127,13 +2127,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:0b,dl_dst=50:54:00:00:00:07,nw_src=10.0.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2ded +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:0b,dl_dst=50:54:00:00:00:07,nw_src=10.0.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2ded dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:0b,dl_dst=50:54:00:00:00:07,nw_src=10.0.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2ded +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:0b,dl_dst=50:54:00:00:00:07,nw_src=10.0.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2ded dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:0b,dl_dst=50:54:00:00:00:07,nw_src=10.0.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2ded +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:0b,dl_dst=50:54:00:00:00:07,nw_src=10.0.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2ded ]) AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore]) @@ -2154,13 +2154,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=62 in_port=1 (via action) data_len=62 (unbuffered) -mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:01:00,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=31,mpls_bos=1 +mplsm,vlan_tci=0x0000,dl_src=60:66:66:66:01:00,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=31,mpls_bos=1 dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=62 in_port=1 (via action) data_len=62 (unbuffered) -mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:01:00,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=31,mpls_bos=1 +mplsm,vlan_tci=0x0000,dl_src=60:66:66:66:01:00,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=31,mpls_bos=1 dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=62 in_port=1 (via action) data_len=62 (unbuffered) -mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:01:00,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=31,mpls_bos=1 +mplsm,vlan_tci=0x0000,dl_src=60:66:66:66:01:00,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=31,mpls_bos=1 ]) AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore]) @@ -2181,13 +2181,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=62 in_port=1 (via action) data_len=62 (unbuffered) -mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:01:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=30,mpls_bos=1 +mpls,vlan_tci=0x0000,dl_src=60:66:66:66:01:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=30,mpls_bos=1 dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=62 in_port=1 (via action) data_len=62 (unbuffered) -mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:01:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=30,mpls_bos=1 +mpls,vlan_tci=0x0000,dl_src=60:66:66:66:01:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=30,mpls_bos=1 dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=62 in_port=1 (via action) data_len=62 (unbuffered) -mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:01:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=30,mpls_bos=1 +mpls,vlan_tci=0x0000,dl_src=60:66:66:66:01:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=30,mpls_bos=1 ]) AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore]) @@ -2208,13 +2208,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=62 in_port=1 (via action) data_len=62 (unbuffered) -mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:01:02,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=3,mpls_ttl=31,mpls_bos=1 +mplsm,vlan_tci=0x0000,dl_src=60:66:66:66:01:02,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=3,mpls_ttl=31,mpls_bos=1 dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=62 in_port=1 (via action) data_len=62 (unbuffered) -mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:01:02,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=3,mpls_ttl=31,mpls_bos=1 +mplsm,vlan_tci=0x0000,dl_src=60:66:66:66:01:02,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=3,mpls_ttl=31,mpls_bos=1 dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=62 in_port=1 (via action) data_len=62 (unbuffered) -mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:01:02,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=3,mpls_ttl=31,mpls_bos=1 +mplsm,vlan_tci=0x0000,dl_src=60:66:66:66:01:02,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=3,mpls_ttl=31,mpls_bos=1 ]) AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore]) @@ -2235,13 +2235,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:02:00,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:02:00,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:02:00,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:02:00,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 dnl NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:02:00,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:02:00,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 ]) AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore]) @@ -2263,13 +2263,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:02:01,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:02:01,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 dnl NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:02:01,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:02:01,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 dnl NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:02:01,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:02:01,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 ]) AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore]) @@ -2290,13 +2290,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:02:10,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:02:10,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 dnl NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:02:10,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:02:10,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 dnl NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:02:10,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:02:10,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 ]) AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore]) @@ -2318,13 +2318,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=62 in_port=1 (via action) data_len=62 (unbuffered) -mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:03:00,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=30,mpls_bos=1 +mplsm,vlan_tci=0x0000,dl_src=60:66:66:66:03:00,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=30,mpls_bos=1 dnl NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=62 in_port=1 (via action) data_len=62 (unbuffered) -mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:03:00,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=30,mpls_bos=1 +mplsm,vlan_tci=0x0000,dl_src=60:66:66:66:03:00,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=30,mpls_bos=1 dnl NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=62 in_port=1 (via action) data_len=62 (unbuffered) -mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:03:00,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=30,mpls_bos=1 +mplsm,vlan_tci=0x0000,dl_src=60:66:66:66:03:00,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=30,mpls_bos=1 ]) AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore]) @@ -2346,13 +2346,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=62 in_port=1 (via action) data_len=62 (unbuffered) -mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:03:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=29,mpls_bos=1 +mpls,vlan_tci=0x0000,dl_src=60:66:66:66:03:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=29,mpls_bos=1 dnl NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=62 in_port=1 (via action) data_len=62 (unbuffered) -mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:03:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=29,mpls_bos=1 +mpls,vlan_tci=0x0000,dl_src=60:66:66:66:03:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=29,mpls_bos=1 dnl NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=62 in_port=1 (via action) data_len=62 (unbuffered) -mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:03:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=29,mpls_bos=1 +mpls,vlan_tci=0x0000,dl_src=60:66:66:66:03:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=29,mpls_bos=1 ]) AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore]) @@ -2374,13 +2374,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=62 in_port=1 (via action) data_len=62 (unbuffered) -mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:03:10,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=29,mpls_bos=1 +mplsm,vlan_tci=0x0000,dl_src=60:66:66:66:03:10,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=29,mpls_bos=1 dnl NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=62 in_port=1 (via action) data_len=62 (unbuffered) -mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:03:10,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=29,mpls_bos=1 +mplsm,vlan_tci=0x0000,dl_src=60:66:66:66:03:10,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=29,mpls_bos=1 dnl NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=62 in_port=1 (via action) data_len=62 (unbuffered) -mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:03:10,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=29,mpls_bos=1 +mplsm,vlan_tci=0x0000,dl_src=60:66:66:66:03:10,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=29,mpls_bos=1 ]) AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore]) @@ -2400,13 +2400,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0xf total_len=62 in_port=1 (via action) data_len=62 (unbuffered) -mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:04:00,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=255,mpls_bos=1 +mpls,vlan_tci=0x0000,dl_src=60:66:66:66:04:00,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=255,mpls_bos=1 dnl NXT_PACKET_IN (xid=0x0): cookie=0xf total_len=62 in_port=1 (via action) data_len=62 (unbuffered) -mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:04:00,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=255,mpls_bos=1 +mpls,vlan_tci=0x0000,dl_src=60:66:66:66:04:00,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=255,mpls_bos=1 dnl NXT_PACKET_IN (xid=0x0): cookie=0xf total_len=62 in_port=1 (via action) data_len=62 (unbuffered) -mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:04:00,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=255,mpls_bos=1 +mpls,vlan_tci=0x0000,dl_src=60:66:66:66:04:00,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=255,mpls_bos=1 ]) AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore]) @@ -2426,13 +2426,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0xf total_len=62 in_port=1 (via action) data_len=62 (unbuffered) -mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:04:01,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=254,mpls_bos=1 +mplsm,vlan_tci=0x0000,dl_src=60:66:66:66:04:01,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=254,mpls_bos=1 dnl NXT_PACKET_IN (xid=0x0): cookie=0xf total_len=62 in_port=1 (via action) data_len=62 (unbuffered) -mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:04:01,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=254,mpls_bos=1 +mplsm,vlan_tci=0x0000,dl_src=60:66:66:66:04:01,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=254,mpls_bos=1 dnl NXT_PACKET_IN (xid=0x0): cookie=0xf total_len=62 in_port=1 (via action) data_len=62 (unbuffered) -mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:04:01,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=254,mpls_bos=1 +mplsm,vlan_tci=0x0000,dl_src=60:66:66:66:04:01,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=254,mpls_bos=1 ]) AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore]) @@ -2452,13 +2452,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0xf total_len=62 in_port=1 (via action) data_len=62 (unbuffered) -mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:04:10,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=253,mpls_bos=1 +mplsm,vlan_tci=0x0000,dl_src=60:66:66:66:04:10,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=253,mpls_bos=1 dnl NXT_PACKET_IN (xid=0x0): cookie=0xf total_len=62 in_port=1 (via action) data_len=62 (unbuffered) -mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:04:10,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=253,mpls_bos=1 +mplsm,vlan_tci=0x0000,dl_src=60:66:66:66:04:10,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=253,mpls_bos=1 dnl NXT_PACKET_IN (xid=0x0): cookie=0xf total_len=62 in_port=1 (via action) data_len=62 (unbuffered) -mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:04:10,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=253,mpls_bos=1 +mplsm,vlan_tci=0x0000,dl_src=60:66:66:66:04:10,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=253,mpls_bos=1 ]) AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore]) @@ -2479,13 +2479,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0x5 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) -mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:05:00,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=32,mpls_bos=1 +mpls,vlan_tci=0x0000,dl_src=60:66:66:66:05:00,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=32,mpls_bos=1 dnl NXT_PACKET_IN (xid=0x0): cookie=0x5 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) -mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:05:00,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=32,mpls_bos=1 +mpls,vlan_tci=0x0000,dl_src=60:66:66:66:05:00,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=32,mpls_bos=1 dnl NXT_PACKET_IN (xid=0x0): cookie=0x5 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) -mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:05:00,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=32,mpls_bos=1 +mpls,vlan_tci=0x0000,dl_src=60:66:66:66:05:00,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=32,mpls_bos=1 ]) AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore]) @@ -2505,13 +2505,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0x5 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) -mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:05:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=31,mpls_bos=1 +mplsm,vlan_tci=0x0000,dl_src=60:66:66:66:05:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=31,mpls_bos=1 dnl NXT_PACKET_IN (xid=0x0): cookie=0x5 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) -mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:05:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=31,mpls_bos=1 +mplsm,vlan_tci=0x0000,dl_src=60:66:66:66:05:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=31,mpls_bos=1 dnl NXT_PACKET_IN (xid=0x0): cookie=0x5 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) -mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:05:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=31,mpls_bos=1 +mplsm,vlan_tci=0x0000,dl_src=60:66:66:66:05:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=31,mpls_bos=1 ]) AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore]) @@ -2532,13 +2532,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0x5 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) -mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:05:10,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=31,mpls_bos=1 +mpls,vlan_tci=0x0000,dl_src=60:66:66:66:05:10,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=31,mpls_bos=1 dnl NXT_PACKET_IN (xid=0x0): cookie=0x5 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) -mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:05:10,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=31,mpls_bos=1 +mpls,vlan_tci=0x0000,dl_src=60:66:66:66:05:10,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=31,mpls_bos=1 dnl NXT_PACKET_IN (xid=0x0): cookie=0x5 total_len=62 in_port=1 (via action) data_len=62 (unbuffered) -mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:05:10,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=31,mpls_bos=1 +mpls,vlan_tci=0x0000,dl_src=60:66:66:66:05:10,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=31,mpls_bos=1 ]) AT_CHECK([ovs-appctl revalidator/purge], [0]) @@ -2618,13 +2618,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl OFPT_PACKET_IN (OF1.2) (xid=0x0): table_id=1 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:08,dl_dst=50:54:00:00:00:01,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=32,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:08,dl_dst=50:54:00:00:00:01,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=32,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 dnl OFPT_PACKET_IN (OF1.2) (xid=0x0): table_id=1 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:08,dl_dst=50:54:00:00:00:01,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=32,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:08,dl_dst=50:54:00:00:00:01,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=32,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 dnl OFPT_PACKET_IN (OF1.2) (xid=0x0): table_id=1 total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:08,dl_dst=50:54:00:00:00:01,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=32,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:08,dl_dst=50:54:00:00:00:01,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=32,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 ]) AT_CHECK([ovs-appctl revalidator/purge], [0]) @@ -2667,13 +2667,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl OFPT_PACKET_IN (OF1.2) (xid=0x0): total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:08,dl_dst=50:54:00:00:00:01,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=32,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:08,dl_dst=50:54:00:00:00:01,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=32,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 dnl OFPT_PACKET_IN (OF1.2) (xid=0x0): total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:08,dl_dst=50:54:00:00:00:01,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=32,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:08,dl_dst=50:54:00:00:00:01,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=32,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 dnl OFPT_PACKET_IN (OF1.2) (xid=0x0): total_len=58 in_port=1 (via action) data_len=58 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:08,dl_dst=50:54:00:00:00:01,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=32,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 +tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:08,dl_dst=50:54:00:00:00:01,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=32,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744 ]) AT_CHECK([ovs-appctl revalidator/purge], [0]) @@ -2706,13 +2706,13 @@ ovs-appctl -t ovs-ofctl exit AT_CHECK([cat ofctl_monitor.log], [0], [dnl OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 dnl OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 dnl OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 ]) AT_CHECK([ovs-appctl revalidator/purge], [0]) @@ -2748,13 +2748,13 @@ AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore]) AT_CHECK([cat ofctl_monitor.log], [0], [dnl OFPT_PACKET_IN (OF1.3) (xid=0x0): cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 dnl OFPT_PACKET_IN (OF1.3) (xid=0x0): cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 dnl OFPT_PACKET_IN (OF1.3) (xid=0x0): cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 ]) AT_CHECK([ovs-appctl revalidator/purge], [0]) @@ -2814,13 +2814,13 @@ send: OFPT_SET_ASYNC (OF1.3) (xid=0x2): FLOW_REMOVED: (off) dnl OFPT_PACKET_IN (OF1.3) (xid=0x0): cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 dnl OFPT_PACKET_IN (OF1.3) (xid=0x0): cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 dnl OFPT_PACKET_IN (OF1.3) (xid=0x0): cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 ]) AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore]) @@ -2856,13 +2856,13 @@ ovs-appctl -t ovs-ofctl exit AT_CHECK([ovs-appctl revalidator/purge], [0]) AT_CHECK([cat ofctl_monitor.log], [0], [dnl OFPT_PACKET_IN (OF1.4) (xid=0x0): cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 dnl OFPT_PACKET_IN (OF1.4) (xid=0x0): cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 dnl OFPT_PACKET_IN (OF1.4) (xid=0x0): cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 ]) AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore]) @@ -2904,31 +2904,31 @@ AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore]) AT_CHECK([cat ofctl_monitor.log], [0], [dnl OFPT_PACKET_IN (OF1.3) (xid=0x0): table_id=1 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 dnl OFPT_PACKET_IN (OF1.3) (xid=0x0): table_id=2 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 dnl OFPT_PACKET_IN (OF1.3) (xid=0x0): cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 dnl OFPT_PACKET_IN (OF1.3) (xid=0x0): table_id=1 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 dnl OFPT_PACKET_IN (OF1.3) (xid=0x0): table_id=2 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 dnl OFPT_PACKET_IN (OF1.3) (xid=0x0): cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 dnl OFPT_PACKET_IN (OF1.3) (xid=0x0): table_id=1 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 dnl OFPT_PACKET_IN (OF1.3) (xid=0x0): table_id=2 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 dnl OFPT_PACKET_IN (OF1.3) (xid=0x0): cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 ]) AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore]) @@ -2972,31 +2972,31 @@ AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore]) AT_CHECK([cat ofctl_monitor.log], [0], [dnl OFPT_PACKET_IN (OF1.4) (xid=0x0): table_id=1 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 dnl OFPT_PACKET_IN (OF1.4) (xid=0x0): table_id=2 cookie=0x0 total_len=60 in_port=1 (via group) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 dnl OFPT_PACKET_IN (OF1.4) (xid=0x0): cookie=0x0 total_len=60 in_port=1 (via action_set) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 dnl OFPT_PACKET_IN (OF1.4) (xid=0x0): table_id=1 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 dnl OFPT_PACKET_IN (OF1.4) (xid=0x0): table_id=2 cookie=0x0 total_len=60 in_port=1 (via group) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 dnl OFPT_PACKET_IN (OF1.4) (xid=0x0): cookie=0x0 total_len=60 in_port=1 (via action_set) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 dnl OFPT_PACKET_IN (OF1.4) (xid=0x0): table_id=1 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 dnl OFPT_PACKET_IN (OF1.4) (xid=0x0): table_id=2 cookie=0x0 total_len=60 in_port=1 (via group) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 dnl OFPT_PACKET_IN (OF1.4) (xid=0x0): cookie=0x0 total_len=60 in_port=1 (via action_set) data_len=60 (unbuffered) -tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 +tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0 ]) AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore]) @@ -3200,21 +3200,21 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:00:00,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=64,mpls_bos=1 +mpls,vlan_tci=0x0000,dl_src=40:44:44:44:00:00,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=64,mpls_bos=1 00000000 50 54 00 00 00 07 40 44-44 44 00 00 88 47 00 00 00000010 01 40 45 00 00 28 00 00-00 00 40 06 f9 7c c0 a8 00000020 00 01 c0 a8 00 02 00 00-00 00 00 00 00 00 00 00 00000030 00 00 50 00 00 00 00 00-00 00 00 00 00 00 00 00 dnl OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:00:00,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=64,mpls_bos=1 +mpls,vlan_tci=0x0000,dl_src=40:44:44:44:00:00,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=64,mpls_bos=1 00000000 50 54 00 00 00 07 40 44-44 44 00 00 88 47 00 00 00000010 01 40 45 00 00 28 00 00-00 00 40 06 f9 7c c0 a8 00000020 00 01 c0 a8 00 02 00 00-00 00 00 00 00 00 00 00 00000030 00 00 50 00 00 00 00 00-00 00 00 00 00 00 00 00 dnl OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:00:00,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=64,mpls_bos=1 +mpls,vlan_tci=0x0000,dl_src=40:44:44:44:00:00,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=64,mpls_bos=1 00000000 50 54 00 00 00 07 40 44-44 44 00 00 88 47 00 00 00000010 01 40 45 00 00 28 00 00-00 00 40 06 f9 7c c0 a8 00000020 00 01 c0 a8 00 02 00 00-00 00 00 00 00 00 00 00 @@ -3233,21 +3233,21 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:00:01,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=0,mpls_lse1=41280 +mpls,vlan_tci=0x0000,dl_src=40:44:44:44:00:01,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=0,mpls_lse1=41280 00000000 50 54 00 00 00 07 40 44-44 44 00 01 88 47 00 00 00000010 a0 40 00 00 a1 40 00 00-00 00 00 00 00 00 00 00 00000020 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 00000030 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 dnl OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:00:01,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=0,mpls_lse1=41280 +mpls,vlan_tci=0x0000,dl_src=40:44:44:44:00:01,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=0,mpls_lse1=41280 00000000 50 54 00 00 00 07 40 44-44 44 00 01 88 47 00 00 00000010 a0 40 00 00 a1 40 00 00-00 00 00 00 00 00 00 00 00000020 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 00000030 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 dnl OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:00:01,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=0,mpls_lse1=41280 +mpls,vlan_tci=0x0000,dl_src=40:44:44:44:00:01,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=0,mpls_lse1=41280 00000000 50 54 00 00 00 07 40 44-44 44 00 01 88 47 00 00 00000010 a0 40 00 00 a1 40 00 00-00 00 00 00 00 00 00 00 00000020 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 @@ -3268,21 +3268,21 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit]) AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mplsm,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:00:02,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=0,mpls_lse1=41280 +mplsm,vlan_tci=0x0000,dl_src=40:44:44:44:00:02,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=0,mpls_lse1=41280 00000000 50 54 00 00 00 07 40 44-44 44 00 02 88 48 00 00 00000010 a0 40 00 00 a1 40 00 00-00 00 00 00 00 00 00 00 00000020 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 00000030 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 dnl OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mplsm,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:00:02,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=0,mpls_lse1=41280 +mplsm,vlan_tci=0x0000,dl_src=40:44:44:44:00:02,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=0,mpls_lse1=41280 00000000 50 54 00 00 00 07 40 44-44 44 00 02 88 48 00 00 00000010 a0 40 00 00 a1 40 00 00-00 00 00 00 00 00 00 00 00000020 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 00000030 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 dnl OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mplsm,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:00:02,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=0,mpls_lse1=41280 +mplsm,vlan_tci=0x0000,dl_src=40:44:44:44:00:02,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=0,mpls_lse1=41280 00000000 50 54 00 00 00 07 40 44-44 44 00 02 88 48 00 00 00000010 a0 40 00 00 a1 40 00 00-00 00 00 00 00 00 00 00 00000020 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 @@ -3326,7 +3326,7 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl OFPT_PACKET_IN (OF1.2): total_len=68 in_port=1 (via action) data_len=68 (unbuffered) -mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:50,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 +mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:50,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 00000000 50 54 00 00 00 07 40 44-44 44 54 50 81 00 20 63 00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06 00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00 @@ -3334,7 +3334,7 @@ mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:50,dl_dst=50:54:00 00000040 00 00 00 00 dnl OFPT_PACKET_IN (OF1.2): total_len=68 in_port=1 (via action) data_len=68 (unbuffered) -mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:50,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 +mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:50,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 00000000 50 54 00 00 00 07 40 44-44 44 54 50 81 00 20 63 00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06 00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00 @@ -3342,7 +3342,7 @@ mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:50,dl_dst=50:54:00 00000040 00 00 00 00 dnl OFPT_PACKET_IN (OF1.2): total_len=68 in_port=1 (via action) data_len=68 (unbuffered) -mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:50,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 +mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:50,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 00000000 50 54 00 00 00 07 40 44-44 44 54 50 81 00 20 63 00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06 00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00 @@ -3363,21 +3363,21 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:51,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 +mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:51,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 00000000 50 54 00 00 00 07 40 44-44 44 54 51 81 00 20 63 00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06 00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00 00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00 dnl OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:51,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 +mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:51,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 00000000 50 54 00 00 00 07 40 44-44 44 54 51 81 00 20 63 00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06 00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00 00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00 dnl OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:51,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 +mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:51,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 00000000 50 54 00 00 00 07 40 44-44 44 54 51 81 00 20 63 00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06 00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00 @@ -3397,7 +3397,7 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl OFPT_PACKET_IN (OF1.2): total_len=68 in_port=1 (via action) data_len=68 (unbuffered) -mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:52,dl_dst=52:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 +mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:52,dl_dst=52:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 00000000 52 54 00 00 00 07 40 44-44 44 54 52 81 00 20 63 00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06 00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00 @@ -3405,7 +3405,7 @@ mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:52,dl_dst=52:54:00 00000040 00 00 00 00 dnl OFPT_PACKET_IN (OF1.2): total_len=68 in_port=1 (via action) data_len=68 (unbuffered) -mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:52,dl_dst=52:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 +mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:52,dl_dst=52:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 00000000 52 54 00 00 00 07 40 44-44 44 54 52 81 00 20 63 00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06 00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00 @@ -3413,7 +3413,7 @@ mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:52,dl_dst=52:54:00 00000040 00 00 00 00 dnl OFPT_PACKET_IN (OF1.2): total_len=68 in_port=1 (via action) data_len=68 (unbuffered) -mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:52,dl_dst=52:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 +mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:52,dl_dst=52:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 00000000 52 54 00 00 00 07 40 44-44 44 54 52 81 00 20 63 00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06 00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00 @@ -3434,21 +3434,21 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:53,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 +mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:53,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 00000000 50 54 00 00 00 07 40 44-44 44 54 53 81 00 20 63 00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06 00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00 00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00 dnl OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:53,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 +mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:53,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 00000000 50 54 00 00 00 07 40 44-44 44 54 53 81 00 20 63 00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06 00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00 00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00 dnl OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:53,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 +mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:53,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 00000000 50 54 00 00 00 07 40 44-44 44 54 53 81 00 20 63 00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06 00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00 @@ -3468,7 +3468,7 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl OFPT_PACKET_IN (OF1.2): total_len=68 in_port=1 (via action) data_len=68 (unbuffered) -mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:54,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 +mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:54,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 00000000 50 54 00 00 00 07 40 44-44 44 54 54 81 00 20 63 00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06 00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00 @@ -3476,7 +3476,7 @@ mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:54,dl_dst=50:54:00 00000040 00 00 00 00 dnl OFPT_PACKET_IN (OF1.2): total_len=68 in_port=1 (via action) data_len=68 (unbuffered) -mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:54,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 +mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:54,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 00000000 50 54 00 00 00 07 40 44-44 44 54 54 81 00 20 63 00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06 00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00 @@ -3484,7 +3484,7 @@ mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:54,dl_dst=50:54:00 00000040 00 00 00 00 dnl OFPT_PACKET_IN (OF1.2): total_len=68 in_port=1 (via action) data_len=68 (unbuffered) -mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:54,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 +mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:54,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 00000000 50 54 00 00 00 07 40 44-44 44 54 54 81 00 20 63 00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06 00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00 @@ -3505,21 +3505,21 @@ OVS_APP_EXIT_AND_WAIT([ovs-ofctl]) AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:55,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 +mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:55,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 00000000 50 54 00 00 00 07 40 44-44 44 54 55 81 00 20 63 00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06 00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00 00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00 dnl OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:55,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 +mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:55,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 00000000 50 54 00 00 00 07 40 44-44 44 54 55 81 00 20 63 00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06 00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00 00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00 dnl OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:55,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 +mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:55,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 00000000 50 54 00 00 00 07 40 44-44 44 54 55 81 00 20 63 00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06 00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00 @@ -3539,7 +3539,7 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl OFPT_PACKET_IN (OF1.2): total_len=68 in_port=1 (via action) data_len=68 (unbuffered) -mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:56,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 +mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:56,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 00000000 50 54 00 00 00 07 40 44-44 44 54 56 81 00 20 63 00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06 00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00 @@ -3547,7 +3547,7 @@ mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:56,dl_dst=50:54:00 00000040 00 00 00 00 dnl OFPT_PACKET_IN (OF1.2): total_len=68 in_port=1 (via action) data_len=68 (unbuffered) -mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:56,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 +mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:56,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 00000000 50 54 00 00 00 07 40 44-44 44 54 56 81 00 20 63 00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06 00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00 @@ -3555,7 +3555,7 @@ mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:56,dl_dst=50:54:00 00000040 00 00 00 00 dnl OFPT_PACKET_IN (OF1.2): total_len=68 in_port=1 (via action) data_len=68 (unbuffered) -mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:56,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 +mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:56,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 00000000 50 54 00 00 00 07 40 44-44 44 54 56 81 00 20 63 00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06 00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00 @@ -3576,21 +3576,21 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:57,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 +mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:57,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 00000000 50 54 00 00 00 07 40 44-44 44 54 57 81 00 20 63 00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06 00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00 00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00 dnl OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:57,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 +mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:57,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 00000000 50 54 00 00 00 07 40 44-44 44 54 57 81 00 20 63 00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06 00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00 00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00 dnl OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:57,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 +mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:57,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 00000000 50 54 00 00 00 07 40 44-44 44 54 57 81 00 20 63 00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06 00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00 @@ -3610,21 +3610,21 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl) AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:58,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 +mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:58,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 00000000 50 54 00 00 00 07 40 44-44 44 54 58 81 00 20 63 00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06 00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00 00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00 dnl OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:58,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 +mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:58,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 00000000 50 54 00 00 00 07 40 44-44 44 54 58 81 00 20 63 00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06 00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00 00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00 dnl OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:58,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 +mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:58,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 00000000 50 54 00 00 00 07 40 44-44 44 54 58 81 00 20 63 00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06 00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00 @@ -3644,21 +3644,21 @@ ovs-appctl -t ovs-ofctl exit AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:59,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 +mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:59,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 00000000 50 54 00 00 00 07 40 44-44 44 54 59 81 00 20 63 00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06 00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00 00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00 dnl OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:59,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 +mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:59,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 00000000 50 54 00 00 00 07 40 44-44 44 54 59 81 00 20 63 00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06 00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00 00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00 dnl OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:59,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 +mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:59,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1 00000000 50 54 00 00 00 07 40 44-44 44 54 59 81 00 20 63 00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06 00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00 @@ -6391,13 +6391,13 @@ done OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit]) AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): total_len=14 in_port=CONTROLLER (via action) data_len=14 (unbuffered) -in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234 +vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234 dnl NXT_PACKET_IN (xid=0x0): total_len=14 in_port=CONTROLLER (via action) data_len=14 (unbuffered) -in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234 +vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234 dnl NXT_PACKET_IN (xid=0x0): total_len=14 in_port=CONTROLLER (via action) data_len=14 (unbuffered) -in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234 +vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234 ]) AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl @@ -6442,13 +6442,13 @@ done OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit]) AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=14 in_port=1 (via no_match) data_len=14 (unbuffered) -in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234 +vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234 dnl NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=14 in_port=1 (via no_match) data_len=14 (unbuffered) -in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234 +vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234 dnl NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=14 in_port=1 (via no_match) data_len=14 (unbuffered) -in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234 +vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234 ]) (printf "OFPST_TABLE reply (OF1.3) (xid=0x2):" @@ -6498,13 +6498,13 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6]) OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit]) AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234 +vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234 dnl NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234 +vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234 dnl NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234 +vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234 ]) AT_CHECK([ovs-appctl revalidator/purge], [0]) @@ -6551,13 +6551,13 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6]) OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit]) AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234 +vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234 dnl NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234 +vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234 dnl NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered) -in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234 +vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234 ]) AT_CHECK([ovs-appctl revalidator/purge], [0]) @@ -6598,7 +6598,7 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit]) AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=86 in_port=1 (via no_match) data_len=86 (unbuffered) -icmp6,in_port=0,vlan_tci=0x0000,dl_src=00:00:86:05:80:da,dl_dst=00:60:97:07:69:ea,ipv6_src=fe80::200:86ff:fe05:80da,ipv6_dst=fe80::260:97ff:fe07:69ea,ipv6_label=0x00000,nw_tos=0,nw_ecn=0,nw_ttl=255,icmp_type=135,icmp_code=0,nd_target=fe80::260:97ff:fe07:69ea,nd_sll=00:00:86:05:80:da,nd_tll=00:00:00:00:00:00 icmp6_csum:68bd +icmp6,vlan_tci=0x0000,dl_src=00:00:86:05:80:da,dl_dst=00:60:97:07:69:ea,ipv6_src=fe80::200:86ff:fe05:80da,ipv6_dst=fe80::260:97ff:fe07:69ea,ipv6_label=0x00000,nw_tos=0,nw_ecn=0,nw_ttl=255,icmp_type=135,icmp_code=0,nd_target=fe80::260:97ff:fe07:69ea,nd_sll=00:00:86:05:80:da,nd_tll=00:00:00:00:00:00 icmp6_csum:68bd ]) OVS_VSWITCHD_STOP @@ -6619,7 +6619,7 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit]) AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=86 in_port=1 (via action) data_len=86 (unbuffered) -icmp6,in_port=0,vlan_tci=0x0000,dl_src=00:00:86:05:80:da,dl_dst=00:60:97:07:69:ea,ipv6_src=fe80::200:86ff:fe05:80da,ipv6_dst=fe80::260:97ff:fe07:69ea,ipv6_label=0x00000,nw_tos=0,nw_ecn=0,nw_ttl=255,icmp_type=135,icmp_code=0,nd_target=fe80::1,nd_sll=32:21:14:86:11:74,nd_tll=00:00:00:00:00:00 icmp6_csum:19d3 +icmp6,vlan_tci=0x0000,dl_src=00:00:86:05:80:da,dl_dst=00:60:97:07:69:ea,ipv6_src=fe80::200:86ff:fe05:80da,ipv6_dst=fe80::260:97ff:fe07:69ea,ipv6_label=0x00000,nw_tos=0,nw_ecn=0,nw_ttl=255,icmp_type=135,icmp_code=0,nd_target=fe80::1,nd_sll=32:21:14:86:11:74,nd_tll=00:00:00:00:00:00 icmp6_csum:19d3 ]) OVS_VSWITCHD_STOP diff --git a/tests/ofproto.at b/tests/ofproto.at index 62629c099..5ae313998 100644 --- a/tests/ofproto.at +++ b/tests/ofproto.at @@ -2037,21 +2037,21 @@ check_async () { ovs-ofctl -v packet-out br0 controller controller '0001020304050010203040501234' if test X"$1" = X"OFPR_ACTION"; then shift; echo >>expout "OFPT_PACKET_IN: total_len=14 in_port=CONTROLLER (via action) data_len=14 (unbuffered) -in_port=0,vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234" +vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234" fi # OFPT_PACKET_IN, OFPR_NO_MATCH (controller_id=123) ovs-ofctl -v packet-out br0 controller 'controller(reason=no_match,id=123)' '0001020304050010203040501234' if test X"$1" = X"OFPR_NO_MATCH"; then shift; echo >>expout "OFPT_PACKET_IN: total_len=14 in_port=CONTROLLER (via no_match) data_len=14 (unbuffered) -in_port=0,vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234" +vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234" fi # OFPT_PACKET_IN, OFPR_INVALID_TTL (controller_id=0) ovs-ofctl packet-out br0 controller dec_ttl '002583dfb4000026b98cb0f908004500003eb7e200000011339bac11370dac100002d7730035002b8f6d86fb0100000100000000000006626c702d7873066e696369726103636f6d00000f00' if test X"$1" = X"OFPR_INVALID_TTL"; then shift; echo >>expout "OFPT_PACKET_IN: total_len=76 in_port=CONTROLLER (via invalid_ttl) data_len=76 (unbuffered) -udp,in_port=0,vlan_tci=0x0000,dl_src=00:26:b9:8c:b0:f9,dl_dst=00:25:83:df:b4:00,nw_src=172.17.55.13,nw_dst=172.16.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=55155,tp_dst=53 udp_csum:8f6d" +udp,vlan_tci=0x0000,dl_src=00:26:b9:8c:b0:f9,dl_dst=00:25:83:df:b4:00,nw_src=172.17.55.13,nw_dst=172.16.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=55155,tp_dst=53 udp_csum:8f6d" fi # OFPT_PORT_STATUS, OFPPR_ADD @@ -2141,21 +2141,21 @@ check_async () { ovs-ofctl -O OpenFlow12 -v packet-out br0 none controller '0001020304050010203040501234' if test X"$1" = X"OFPR_ACTION"; then shift; echo >>expout "OFPT_PACKET_IN (OF1.2): total_len=14 in_port=ANY (via action) data_len=14 (unbuffered) -in_port=0,vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234" +vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234" fi # OFPT_PACKET_IN, OFPR_NO_MATCH (controller_id=123) ovs-ofctl -O OpenFlow12 -v packet-out br0 none 'controller(reason=no_match,id=123)' '0001020304050010203040501234' if test X"$1" = X"OFPR_NO_MATCH"; then shift; echo >>expout "OFPT_PACKET_IN (OF1.2): total_len=14 in_port=ANY (via no_match) data_len=14 (unbuffered) -in_port=0,vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234" +vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234" fi # OFPT_PACKET_IN, OFPR_INVALID_TTL (controller_id=0) ovs-ofctl -O OpenFlow12 packet-out br0 none dec_ttl '002583dfb4000026b98cb0f908004500003eb7e200000011339bac11370dac100002d7730035002b8f6d86fb0100000100000000000006626c702d7873066e696369726103636f6d00000f00' if test X"$1" = X"OFPR_INVALID_TTL"; then shift; echo >>expout "OFPT_PACKET_IN (OF1.2): total_len=76 in_port=ANY (via invalid_ttl) data_len=76 (unbuffered) -udp,in_port=0,vlan_tci=0x0000,dl_src=00:26:b9:8c:b0:f9,dl_dst=00:25:83:df:b4:00,nw_src=172.17.55.13,nw_dst=172.16.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=55155,tp_dst=53 udp_csum:8f6d" +udp,vlan_tci=0x0000,dl_src=00:26:b9:8c:b0:f9,dl_dst=00:25:83:df:b4:00,nw_src=172.17.55.13,nw_dst=172.16.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=55155,tp_dst=53 udp_csum:8f6d" fi # OFPT_PORT_STATUS, OFPPR_ADD @@ -2245,21 +2245,21 @@ check_async () { ovs-ofctl -O OpenFlow13 -v packet-out br0 none controller '0001020304050010203040501234' if test X"$1" = X"OFPR_ACTION"; then shift; echo >>expout "OFPT_PACKET_IN (OF1.3): total_len=14 in_port=ANY (via action) data_len=14 (unbuffered) -in_port=0,vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234" +vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234" fi # OFPT_PACKET_IN, OFPR_NO_MATCH (controller_id=123) ovs-ofctl -O OpenFlow13 -v packet-out br0 none 'controller(reason=no_match,id=123)' '0001020304050010203040501234' if test X"$1" = X"OFPR_NO_MATCH"; then shift; echo >>expout "OFPT_PACKET_IN (OF1.3): total_len=14 in_port=ANY (via no_match) data_len=14 (unbuffered) -in_port=0,vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234" +vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234" fi # OFPT_PACKET_IN, OFPR_INVALID_TTL (controller_id=0) ovs-ofctl -O OpenFlow13 packet-out br0 none dec_ttl '002583dfb4000026b98cb0f908004500003eb7e200000011339bac11370dac100002d7730035002b8f6d86fb0100000100000000000006626c702d7873066e696369726103636f6d00000f00' if test X"$1" = X"OFPR_INVALID_TTL"; then shift; echo >>expout "OFPT_PACKET_IN (OF1.3): total_len=76 in_port=ANY (via invalid_ttl) data_len=76 (unbuffered) -udp,in_port=0,vlan_tci=0x0000,dl_src=00:26:b9:8c:b0:f9,dl_dst=00:25:83:df:b4:00,nw_src=172.17.55.13,nw_dst=172.16.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=55155,tp_dst=53 udp_csum:8f6d" +udp,vlan_tci=0x0000,dl_src=00:26:b9:8c:b0:f9,dl_dst=00:25:83:df:b4:00,nw_src=172.17.55.13,nw_dst=172.16.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=55155,tp_dst=53 udp_csum:8f6d" fi # OFPT_PORT_STATUS, OFPPR_ADD @@ -2567,9 +2567,9 @@ ovs-ofctl dump-ports br0 AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//' monitor.log], [0], [dnl OFPT_PACKET_IN: total_len=14 in_port=ANY (via action) data_len=14 (unbuffered) -in_port=0,vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234 +vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234 OFPT_PACKET_IN: total_len=14 in_port=CONTROLLER (via action) data_len=14 (unbuffered) -in_port=0,vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x5678 +vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x5678 OFPT_BARRIER_REPLY: ]) @@ -2600,9 +2600,9 @@ ovs-appctl -t ovs-ofctl exit AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//' monitor.log], [0], [dnl OFPT_PACKET_IN (OF1.2): total_len=14 in_port=ANY (via action) data_len=14 (unbuffered) -in_port=0,vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234 +vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234 OFPT_PACKET_IN (OF1.2): total_len=14 in_port=CONTROLLER (via action) data_len=14 (unbuffered) -in_port=0,vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x5678 +vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x5678 OFPT_BARRIER_REPLY (OF1.2): ]) @@ -2633,9 +2633,9 @@ ovs-appctl -t ovs-ofctl exit AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//' monitor.log], [0], [dnl OFPT_PACKET_IN (OF1.1): total_len=14 in_port=ANY (via action) data_len=14 (unbuffered) -in_port=0,vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234 +vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234 OFPT_PACKET_IN (OF1.1): total_len=14 in_port=CONTROLLER (via action) data_len=14 (unbuffered) -in_port=0,vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x5678 +vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x5678 OFPT_BARRIER_REPLY (OF1.1): ]) @@ -2663,7 +2663,7 @@ ovs-appctl -t ovs-ofctl exit AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//' monitor.log], [0], [dnl NXT_PACKET_IN: total_len=14 in_port=CONTROLLER metadata=0xfafafafa5a5a5a5a pkt_mark=0xaa (via action) data_len=14 (unbuffered) -in_port=0,vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234 +vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234 OFPT_BARRIER_REPLY: ]) @@ -2691,7 +2691,7 @@ ovs-appctl -t ovs-ofctl exit AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//' monitor.log], [0], [dnl OFPT_PACKET_IN (OF1.2): total_len=14 in_port=ANY metadata=0xfafafafa5a5a5a5a (via action) data_len=14 (unbuffered) -in_port=0,vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234 +vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234 OFPT_BARRIER_REPLY (OF1.2): ]) @@ -2719,7 +2719,7 @@ ovs-appctl -t ovs-ofctl exit AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//' monitor.log], [0], [dnl OFPT_PACKET_IN (OF1.3): total_len=14 in_port=ANY metadata=0x6b (via action) data_len=14 (unbuffered) -in_port=0,vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234 +vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234 OFPT_BARRIER_REPLY (OF1.3): ]) @@ -2746,7 +2746,7 @@ ovs-appctl -t ovs-ofctl exit AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//' monitor.log], [0], [dnl OFPT_PACKET_IN (OF1.2): total_len=14 in_port=ANY tun_id=0x1020304 tun_src=127.0.0.1 tun_dst=192.168.0.1 (via action) data_len=14 (unbuffered) -in_port=0,vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234 +vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234 OFPT_BARRIER_REPLY (OF1.2): ]) -- cgit v1.2.1 From c876a4bb9bcc881befac5647a1e311b5af09d549 Mon Sep 17 00:00:00 2001 From: Ricky Li Date: Thu, 26 Mar 2015 06:11:28 -0700 Subject: netdev: Fix user space tunneling for set_tunnel action. e.g. Set tunnel id for encapsulated VxLAN packet (out_key=flow): ovs-vsctl add-port int-br vxlan0 -- set interface vxlan0 \ type=vxlan options:remote_ip=172.168.1.2 options:out_key=flow ovs-ofctl add-flow int-br in_port=LOCAL, icmp,\ actions=set_tunnel:3, output:1 (1 is the port# of vxlan0) Output tunnel ID should be modified to 3 with this patch. Signed-off-by: Ricky Li Acked-by: Pravin B Shelar --- lib/netdev-provider.h | 3 ++- lib/netdev-vport.c | 10 ++++++---- lib/netdev.c | 6 ++++-- lib/netdev.h | 4 +++- ofproto/tunnel.c | 2 +- tests/tunnel-push-pop.at | 15 ++++++++++++++- 6 files changed, 30 insertions(+), 10 deletions(-) diff --git a/lib/netdev-provider.h b/lib/netdev-provider.h index 915e54a41..fabeb2d41 100644 --- a/lib/netdev-provider.h +++ b/lib/netdev-provider.h @@ -257,7 +257,8 @@ struct netdev_class { /* Build Partial Tunnel header. Ethernet and ip header is already built, * build_header() is suppose build protocol specific part of header. */ - int (*build_header)(const struct netdev *, struct ovs_action_push_tnl *data); + int (*build_header)(const struct netdev *, struct ovs_action_push_tnl *data, + const struct flow *tnl_flow); /* build_header() can not build entire header for all packets for given * flow. Push header is called for packet to build header specific to diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c index 954ab9bd5..c7f3437df 100644 --- a/lib/netdev-vport.c +++ b/lib/netdev-vport.c @@ -1011,7 +1011,8 @@ netdev_gre_push_header(const struct netdev *netdev OVS_UNUSED, static int netdev_gre_build_header(const struct netdev *netdev, - struct ovs_action_push_tnl *data) + struct ovs_action_push_tnl *data, + const struct flow *tnl_flow) { struct netdev_vport *dev = netdev_vport_cast(netdev); struct netdev_tunnel_config *tnl_cfg; @@ -1041,7 +1042,7 @@ netdev_gre_build_header(const struct netdev *netdev, if (tnl_cfg->out_key_present) { greh->flags |= htons(GRE_KEY); put_16aligned_be32(options, (OVS_FORCE ovs_be32) - ((OVS_FORCE uint64_t) tnl_cfg->out_key >> 32)); + ((OVS_FORCE uint64_t) tnl_flow->tunnel.tun_id >> 32)); options++; } @@ -1103,7 +1104,8 @@ netdev_vxlan_pop_header(struct netdev *netdev_ OVS_UNUSED, static int netdev_vxlan_build_header(const struct netdev *netdev, - struct ovs_action_push_tnl *data) + struct ovs_action_push_tnl *data, + const struct flow *tnl_flow) { struct netdev_vport *dev = netdev_vport_cast(netdev); struct netdev_tunnel_config *tnl_cfg; @@ -1123,7 +1125,7 @@ netdev_vxlan_build_header(const struct netdev *netdev, vxh = (struct vxlanhdr *) (udp + 1); put_16aligned_be32(&vxh->vx_flags, htonl(VXLAN_FLAGS)); - put_16aligned_be32(&vxh->vx_vni, htonl(ntohll(tnl_cfg->out_key) << 8)); + put_16aligned_be32(&vxh->vx_vni, htonl(ntohll(tnl_flow->tunnel.tun_id) << 8)); ovs_mutex_unlock(&dev->mutex); data->header_len = VXLAN_HLEN; diff --git a/lib/netdev.c b/lib/netdev.c index 149b39a77..c1d9b8fa5 100644 --- a/lib/netdev.c +++ b/lib/netdev.c @@ -43,6 +43,7 @@ #include "sset.h" #include "svec.h" #include "openvswitch/vlog.h" +#include "flow.h" VLOG_DEFINE_THIS_MODULE(netdev); @@ -740,10 +741,11 @@ netdev_pop_header(struct netdev *netdev, struct dp_packet **buffers, int cnt) } int -netdev_build_header(const struct netdev *netdev, struct ovs_action_push_tnl *data) +netdev_build_header(const struct netdev *netdev, struct ovs_action_push_tnl *data, + const struct flow *tnl_flow) { if (netdev->netdev_class->build_header) { - return netdev->netdev_class->build_header(netdev, data); + return netdev->netdev_class->build_header(netdev, data, tnl_flow); } return EOPNOTSUPP; } diff --git a/lib/netdev.h b/lib/netdev.h index 9a647f0be..71c0af1b5 100644 --- a/lib/netdev.h +++ b/lib/netdev.h @@ -22,6 +22,7 @@ #include #include "openvswitch/types.h" #include "packets.h" +#include "flow.h" #ifdef __cplusplus extern "C" { @@ -184,7 +185,8 @@ int netdev_send(struct netdev *, int qid, struct dp_packet **, int cnt, bool may_steal); void netdev_send_wait(struct netdev *, int qid); -int netdev_build_header(const struct netdev *, struct ovs_action_push_tnl *data); +int netdev_build_header(const struct netdev *, struct ovs_action_push_tnl *data, + const struct flow *tnl_flow); int netdev_push_header(const struct netdev *netdev, struct dp_packet **buffers, int cnt, const struct ovs_action_push_tnl *data); diff --git a/ofproto/tunnel.c b/ofproto/tunnel.c index f621efbe9..3ea0eb44f 100644 --- a/ofproto/tunnel.c +++ b/ofproto/tunnel.c @@ -709,7 +709,7 @@ tnl_port_build_header(const struct ofport_dpif *ofport, put_16aligned_be32(&ip->ip_src, ip_src); put_16aligned_be32(&ip->ip_dst, tnl_flow->tunnel.ip_dst); - res = netdev_build_header(tnl_port->netdev, data); + res = netdev_build_header(tnl_port->netdev, data, tnl_flow); ip->ip_csum = csum(ip, sizeof *ip); fat_rwlock_unlock(&rwlock); diff --git a/tests/tunnel-push-pop.at b/tests/tunnel-push-pop.at index f1fac7f89..6e1c0c116 100644 --- a/tests/tunnel-push-pop.at +++ b/tests/tunnel-push-pop.at @@ -7,7 +7,10 @@ AT_CHECK([ovs-vsctl add-br int-br -- set bridge int-br datapath_type=dummy], [0] AT_CHECK([ovs-vsctl add-port int-br t2 -- set Interface t2 type=vxlan \ options:remote_ip=1.1.2.92 options:key=123 ofport_request=2\ -- add-port int-br t1 -- set Interface t1 type=gre \ - options:remote_ip=1.1.2.92 options:key=456 ofport_request=3], [0]) + options:remote_ip=1.1.2.92 options:key=456 ofport_request=3\ + -- add-port int-br t3 -- set Interface t3 type=vxlan \ + options:remote_ip=1.1.2.93 options:out_key=flow ofport_request=4\ + ], [0]) AT_CHECK([ovs-appctl dpif/show], [0], [dnl dummy@ovs-dummy: hit:0 missed:0 @@ -18,6 +21,7 @@ dummy@ovs-dummy: hit:0 missed:0 int-br 65534/2: (dummy) t1 3/3: (gre: key=456, remote_ip=1.1.2.92) t2 2/4789: (vxlan: key=123, remote_ip=1.1.2.92) + t3 4/4789: (vxlan: out_key=flow, remote_ip=1.1.2.93) ]) AT_CHECK([ovs-appctl ovs/route/add 1.1.2.92/24 br0], [0], [OK @@ -29,11 +33,13 @@ AT_CHECK([ovs-ofctl add-flow br0 action=normal]) dnl Check ARP Snoop AT_CHECK([ovs-appctl netdev-dummy/receive br0 'recirc_id(0),in_port(100),eth(src=f8:bc:12:44:34:b6,dst=ff:ff:ff:ff:ff:ff),eth_type(0x0806),arp(sip=1.1.2.92,tip=1.1.2.88,op=1,sha=f8:bc:12:44:34:b6,tha=00:00:00:00:00:00)']) +AT_CHECK([ovs-appctl netdev-dummy/receive br0 'recirc_id(0),in_port(100),eth(src=f8:bc:12:44:34:b7,dst=ff:ff:ff:ff:ff:ff),eth_type(0x0806),arp(sip=1.1.2.93,tip=1.1.2.88,op=1,sha=f8:bc:12:44:34:b7,tha=00:00:00:00:00:00)']) AT_CHECK([ovs-appctl tnl/arp/show], [0], [dnl IP MAC Bridge ============================================= 1.1.2.92 f8:bc:12:44:34:b6 br0 +1.1.2.93 f8:bc:12:44:34:b7 br0 ]) dnl Check VXLAN tunnel pop @@ -55,6 +61,13 @@ AT_CHECK([tail -1 stdout], [0], [Datapath actions: tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=4789),vxlan(flags=0x8000000,vni=0x7b00)),out_port(100)) ]) +dnl Check VXLAN tunnel push set tunnel id by flow +AT_CHECK([ovs-ofctl add-flow int-br "actions=set_tunnel:124,4"]) +AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout]) +AT_CHECK([tail -1 stdout], [0], + [Datapath actions: tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b7,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.93,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=4789),vxlan(flags=0x8000000,vni=0x7c00)),out_port(100)) +]) + dnl Check GRE tunnel push AT_CHECK([ovs-ofctl add-flow int-br action=3]) AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout]) -- cgit v1.2.1 From 6b2771c347547b835cf425878d1d3e636631b1d5 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Wed, 25 Mar 2015 22:25:50 -0700 Subject: ovs-sandbox: Initialize database before starting ovs-vswitchd. Otherwise ovs-vswitchd can't immediately start working (until some other call to ovs-vsctl initializes the database). This is most obvious if one runs "ovs-vsctl list Open_vSwitch ." as the first command, because the output will not show the changes that ovs-vswitchd will make to the database at startup (in particular initializing datapath_types and iface_types), which is confusing. Signed-off-by: Ben Pfaff Acked-by: Russell Bryant --- tutorial/ovs-sandbox | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tutorial/ovs-sandbox b/tutorial/ovs-sandbox index 1504ea9f8..9520a41c4 100755 --- a/tutorial/ovs-sandbox +++ b/tutorial/ovs-sandbox @@ -1,6 +1,6 @@ #! /bin/sh # -# Copyright (c) 2013 Nicira, Inc. +# Copyright (c) 2013, 2015 Nicira, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -235,6 +235,9 @@ run ovsdb-tool create conf.db "$schema" rungdb $gdb_ovsdb ovsdb-server --detach --no-chdir --pidfile -vconsole:off --log-file \ --remote=punix:"$sandbox"/db.sock +# Initialize database. +run ovs-vsctl --no-wait -- init + # Start ovs-vswitchd. rungdb $gdb_vswitchd ovs-vswitchd --detach --no-chdir --pidfile -vconsole:off --log-file \ --enable-dummy=override -vvconn -vnetdev_dummy -- cgit v1.2.1 From c1ddf0915c4ebdf8626d9fbeb91fab8e7719cd9a Mon Sep 17 00:00:00 2001 From: Flavio Leitner Date: Thu, 26 Mar 2015 21:12:17 -0300 Subject: openvswitch-fedora: remove requires to kernel That RPM requires helped to work around a bug in the kernel that was triggered by userspace package. However, it doesn't force the kernel to be running, so it's a weak solution. Also, it makes difficult to re-use the same spec on other RPM distros. This patch comments out the requires. Signed-off-by: Flavio Leitner Acked-by: Russell Bryant Signed-off-by: Ben Pfaff --- rhel/openvswitch-fedora.spec.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rhel/openvswitch-fedora.spec.in b/rhel/openvswitch-fedora.spec.in index 4889321a4..f3dbebfcf 100644 --- a/rhel/openvswitch-fedora.spec.in +++ b/rhel/openvswitch-fedora.spec.in @@ -38,7 +38,7 @@ BuildRequires: groff graphviz Requires: openssl iproute module-init-tools #Upstream kernel commit 4f647e0a3c37b8d5086214128614a136064110c3 -Requires: kernel >= 3.15.0-0 +#Requires: kernel >= 3.15.0-0 Requires(post): systemd-units Requires(preun): systemd-units -- cgit v1.2.1 From a19083996c4f7ec20d5f6abf8ea4e25157cf9820 Mon Sep 17 00:00:00 2001 From: Alex Wang Date: Thu, 26 Mar 2015 17:35:32 -0700 Subject: netdev-vport: Do not update netdev when there is no config change. When there is any update from ovsdb, ovs will call netdev_set_config() for every vport. Even though the change is not related to vport, the current implementation will always increment the per-netdev sequence number. Subsequently this could cause even more unwanted effects, e.g. the recreation of 'struct tnl_port' in ofproto level. This commit fixes the issue by only updating the netdev when there is actual configuration change. Signed-off-by: Alex Wang Acked-by: Ben Pfaff --- lib/netdev-vport.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c index c7f3437df..211edc732 100644 --- a/lib/netdev-vport.c +++ b/lib/netdev-vport.c @@ -612,9 +612,11 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args) &tnl_cfg.out_key_flow); ovs_mutex_lock(&dev->mutex); - dev->tnl_cfg = tnl_cfg; - tunnel_check_status_change__(dev); - netdev_change_seq_changed(dev_); + if (memcmp(&dev->tnl_cfg, &tnl_cfg, sizeof tnl_cfg)) { + dev->tnl_cfg = tnl_cfg; + tunnel_check_status_change__(dev); + netdev_change_seq_changed(dev_); + } ovs_mutex_unlock(&dev->mutex); return 0; @@ -787,9 +789,11 @@ set_patch_config(struct netdev *dev_, const struct smap *args) } ovs_mutex_lock(&dev->mutex); - free(dev->peer); - dev->peer = xstrdup(peer); - netdev_change_seq_changed(dev_); + if (!dev->peer || strcmp(dev->peer, peer)) { + free(dev->peer); + dev->peer = xstrdup(peer); + netdev_change_seq_changed(dev_); + } ovs_mutex_unlock(&dev->mutex); return 0; -- cgit v1.2.1 From 618f44f7a406d6c3e90110420a7fd183d40f1bff Mon Sep 17 00:00:00 2001 From: Kevin Traynor Date: Fri, 27 Mar 2015 11:06:57 -0700 Subject: netdev-dpdk: Put cuse thread into quiescent state. ovsrcu_synchronize() is used when setting virtio_dev to NULL. This results in an ovsrcu_quiesce_end() call which means the cuse thread may not go into quiescent state again for an indefinite time. Add an ovsrcu_quiesce_start() call to prevent this. Signed-off-by: Kevin Traynor Acked-by: Pravin B Shelar --- lib/netdev-dpdk.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c index 4e16f3916..f69154b07 100644 --- a/lib/netdev-dpdk.c +++ b/lib/netdev-dpdk.c @@ -1586,6 +1586,11 @@ destroy_device(volatile struct virtio_net *dev) * setting the virtio_dev to NULL. */ ovsrcu_synchronize(); + /* + * As call to ovsrcu_synchronize() will end the quiescent state, + * put thread back into quiescent state before returning. + */ + ovsrcu_quiesce_start(); } } ovs_mutex_unlock(&dpdk_mutex); @@ -1614,6 +1619,8 @@ static void * start_cuse_session_loop(void *dummy OVS_UNUSED) { pthread_detach(pthread_self()); + /* Put the cuse thread into quiescent state. */ + ovsrcu_quiesce_start(); rte_vhost_driver_session_start(); return NULL; } @@ -1621,7 +1628,6 @@ start_cuse_session_loop(void *dummy OVS_UNUSED) static int dpdk_vhost_class_init(void) { - pthread_t thread; int err = -1; rte_vhost_driver_callback_register(&virtio_net_device_ops); @@ -1637,9 +1643,8 @@ dpdk_vhost_class_init(void) return -1; } - /* start_cuse_session_loop blocks OVS RCU quiescent state, so directly use - * pthread API. */ - return pthread_create(&thread, NULL, start_cuse_session_loop, NULL); + ovs_thread_create("cuse_thread", start_cuse_session_loop, NULL); + return 0; } static void -- cgit v1.2.1 From 4f631ccd515ffb95dbe3f5c22d74b01c64a7d9b8 Mon Sep 17 00:00:00 2001 From: Alex Wang Date: Fri, 27 Mar 2015 11:34:53 -0700 Subject: netdev-linux: Make htb quantum always no less than mtu. Currently, ovs uses hardcoded rate2quantum = 10 for each htb qdisc. When qdisc class's rate is small, the resulting quantum (calculated by min_rate / rate2quantum) will be smaller than MTU. This is not recommended and tc will keep complaining the following in syslog. localhost kernel: HTB: quantum of class 10003 is small. Consider r2q change. localhost kernel: HTB: quantum of class 10004 is small. Consider r2q change. localhost kernel: HTB: quantum of class 10005 is small. Consider r2q change. localhost kernel: HTB: quantum of class 10006 is small. Consider r2q change. To fix the issue, this commit makes ovs always use htb quantum no less than the MTU. Signed-off-by: Alex Wang Acked-by: Ben Pfaff --- lib/netdev-linux.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index 5e6f01ef6..23f98566d 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -3497,6 +3497,7 @@ static const struct tc_ops tc_ops_sfq = { /* HTB traffic control class. */ #define HTB_N_QUEUES 0xf000 +#define HTB_RATE2QUANTUM 10 struct htb { struct tc tc; @@ -3555,7 +3556,7 @@ htb_setup_qdisc__(struct netdev *netdev) nl_msg_put_string(&request, TCA_KIND, "htb"); memset(&opt, 0, sizeof opt); - opt.rate2quantum = 10; + opt.rate2quantum = HTB_RATE2QUANTUM; opt.version = 3; opt.defcls = 1; @@ -3589,6 +3590,11 @@ htb_setup_class__(struct netdev *netdev, unsigned int handle, memset(&opt, 0, sizeof opt); tc_fill_rate(&opt.rate, class->min_rate, mtu); tc_fill_rate(&opt.ceil, class->max_rate, mtu); + /* Makes sure the quantum is at least MTU. Setting quantum will + * make htb ignore the r2q for this class. */ + if ((class->min_rate / HTB_RATE2QUANTUM) < mtu) { + opt.quantum = mtu; + } opt.buffer = tc_calc_buffer(opt.rate.rate, mtu, class->burst); opt.cbuffer = tc_calc_buffer(opt.ceil.rate, mtu, class->burst); opt.prio = class->priority; -- cgit v1.2.1 From 4e5e44e30133939b792a013a812c84f564ffa8aa Mon Sep 17 00:00:00 2001 From: Alex Wang Date: Fri, 27 Mar 2015 23:19:22 -0700 Subject: ofproto-dpif: Set need_revalidate when removing cfm from ofport. When cfm is deleted from a port, all modules should release their reference so that the cfm struct can be removed from the global hmap and freed. Therein, the reference held by xlate module can only be released when the need_revalidate flag is set (e.g set to REV_RECONFIGURE). And this flag should be set while removing cfm from ofport. Unfortunately, this has never been done before and the bug was hidden by another bug fixed in recent commit a190839 (netdev-vport: Do not update netdev when there is no config change.) To fix this issue, this commit makes the code set need_revalidate when removing cfm from ofport. Signed-off-by: Alex Wang Acked-by: Ben Pfaff --- ofproto/ofproto-dpif.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 64024044a..837ae0bd3 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -1915,14 +1915,12 @@ static int set_cfm(struct ofport *ofport_, const struct cfm_settings *s) { struct ofport_dpif *ofport = ofport_dpif_cast(ofport_); + struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofport->up.ofproto); + struct cfm *old = ofport->cfm; int error = 0; if (s) { if (!ofport->cfm) { - struct ofproto_dpif *ofproto; - - ofproto = ofproto_dpif_cast(ofport->up.ofproto); - ofproto->backer->need_revalidate = REV_RECONFIGURE; ofport->cfm = cfm_create(ofport->up.netdev); } @@ -1936,6 +1934,9 @@ set_cfm(struct ofport *ofport_, const struct cfm_settings *s) cfm_unref(ofport->cfm); ofport->cfm = NULL; out: + if (ofport->cfm != old) { + ofproto->backer->need_revalidate = REV_RECONFIGURE; + } ofproto_dpif_monitor_port_update(ofport, ofport->bfd, ofport->cfm, ofport->lldp, ofport->up.pp.hw_addr); return error; -- cgit v1.2.1 From 0d42597cd1b9fa32fdfc6c033c97d28c09087b57 Mon Sep 17 00:00:00 2001 From: Alin Serdean Date: Mon, 30 Mar 2015 15:34:28 +0000 Subject: build-aux/cccl: Enhance --with-debug option This patch changes the behaviour in case the configure argument: --with-debug was specified. Currently the optimization flag in the case of debugging is the following: https://msdn.microsoft.com/en-us/library/f9534wye.aspx which does not fully disable optimization, that is why it was changed with the following flag: https://msdn.microsoft.com/en-us/library/aafb762y.aspx which disables all code optimization. Also this patch includes the definition of the following preprocessor definitions: _DEBUG - in case --with-debug is specified The above definitions usually are defined when compiling with the following flags: https://msdn.microsoft.com/en-us/library/2kzt1wy3.aspx Since we are not compiling with the above flag, mimic the behaviour the debug becahviour. Signed-off-by: Alin Gabriel Serdean Signed-off-by: Gurucharan Shetty Acked-by: Ben Pfaff --- build-aux/cccl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-aux/cccl b/build-aux/cccl index 2a4dccc52..456292e5f 100644 --- a/build-aux/cccl +++ b/build-aux/cccl @@ -90,7 +90,7 @@ EOF ;; -O0) - clopt="$clopt ${slash}Ot" + clopt="$clopt ${slash}Od ${slash}D_DEBUG" ;; -O2) -- cgit v1.2.1 From 7ad20cbd96b9b33a2e01be36dc51674fde8b67bf Mon Sep 17 00:00:00 2001 From: Daniele Di Proietto Date: Fri, 27 Mar 2015 16:29:50 +0000 Subject: dpif-netdev: Account for and free lost packets. Packets for which an upcall has failed (lost packets) must be deleted. We also need to count them as MISS and LOST. Signed-off-by: Daniele Di Proietto Acked-by: Ethan Jackson --- lib/dpif-netdev.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index f01fecb68..6b61db4b6 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -2941,6 +2941,8 @@ fast_path_processing(struct dp_netdev_pmd_thread *pmd, &ufid, DPIF_UC_MISS, NULL, &actions, &put_actions); if (OVS_UNLIKELY(error && error != ENOSPC)) { + dp_packet_delete(packets[i]); + dp_netdev_count_packet(pmd, DP_STAT_LOST, 1); continue; } @@ -2984,6 +2986,7 @@ fast_path_processing(struct dp_netdev_pmd_thread *pmd, } } + dp_netdev_count_packet(pmd, DP_STAT_MISS, dropped_cnt); dp_netdev_count_packet(pmd, DP_STAT_LOST, dropped_cnt); } -- cgit v1.2.1 From 4adb03cb6e62d938b586e68aae7af06587e58f49 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Mon, 30 Mar 2015 12:21:09 +0200 Subject: datapath: Use alternate name for udp_sock_create() backport Account for kernels which provide udp_sock_create() in an insufficient version. Avoids the following error when inserting openvswitch.ko on respective kernels: openvswitch: exports duplicate symbol udp_sock_create (owned by udp_tunnel) Fixes: eb6eebd28 ("datapath: Account for "udp: Add udp_sock_create for UDP tunnels to open listener socket") Signed-off-by: Thomas Graf Cc: Jesse Gross Acked-by: Jesse Gross --- datapath/linux/compat/include/net/udp_tunnel.h | 1 + 1 file changed, 1 insertion(+) diff --git a/datapath/linux/compat/include/net/udp_tunnel.h b/datapath/linux/compat/include/net/udp_tunnel.h index 7dadac16c..6c25ca54b 100644 --- a/datapath/linux/compat/include/net/udp_tunnel.h +++ b/datapath/linux/compat/include/net/udp_tunnel.h @@ -49,6 +49,7 @@ struct udp_port_cfg { use_udp6_rx_checksums:1; }; +#define udp_sock_create rpl_udp_sock_create int udp_sock_create(struct net *net, struct udp_port_cfg *cfg, struct socket **sockp); -- cgit v1.2.1 From 2e2f242e6730a658f077ee4be2b8a9c3f0cc9a04 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Tue, 31 Mar 2015 11:28:27 -0700 Subject: jsonrpc: Add function comments. Signed-off-by: Ben Pfaff Acked-by: Russell Bryant --- lib/jsonrpc.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/lib/jsonrpc.c b/lib/jsonrpc.c index 86531b822..ae51b4299 100644 --- a/lib/jsonrpc.c +++ b/lib/jsonrpc.c @@ -1063,36 +1063,49 @@ jsonrpc_session_recv_wait(struct jsonrpc_session *s) } } +/* Returns true if 's' is currently connected or trying to connect. */ bool jsonrpc_session_is_alive(const struct jsonrpc_session *s) { return s->rpc || s->stream || reconnect_get_max_tries(s->reconnect); } +/* Returns true if 's' is currently connected. */ bool jsonrpc_session_is_connected(const struct jsonrpc_session *s) { return s->rpc != NULL; } +/* Returns a sequence number for 's'. The sequence number increments every + * time 's' connects or disconnects. Thus, a caller can use the change (or + * lack of change) in the sequence number to figure out whether the underlying + * connection is the same as before. */ unsigned int jsonrpc_session_get_seqno(const struct jsonrpc_session *s) { return s->seqno; } +/* Returns the current status of 's'. If 's' is NULL or is disconnected, this + * is 0, otherwise it is the status of the connection, as reported by + * jsonrpc_get_status(). */ int jsonrpc_session_get_status(const struct jsonrpc_session *s) { return s && s->rpc ? jsonrpc_get_status(s->rpc) : 0; } +/* Returns the last error reported on a connection by 's'. The return value is + * 0 only if no connection made by 's' has ever encountered an error. See + * jsonrpc_get_status() for return value interpretation. */ int jsonrpc_session_get_last_error(const struct jsonrpc_session *s) { return s->last_error; } +/* Populates 'stats' with statistics from 's'. */ void jsonrpc_session_get_reconnect_stats(const struct jsonrpc_session *s, struct reconnect_stats *stats) @@ -1100,6 +1113,7 @@ jsonrpc_session_get_reconnect_stats(const struct jsonrpc_session *s, reconnect_get_stats(s->reconnect, time_msec(), stats); } +/* Enables 's' to reconnect to the peer if the connection drops. */ void jsonrpc_session_enable_reconnect(struct jsonrpc_session *s) { @@ -1108,18 +1122,27 @@ jsonrpc_session_enable_reconnect(struct jsonrpc_session *s) RECONNECT_DEFAULT_MAX_BACKOFF); } +/* Forces 's' to drop its connection (if any) and reconnect. */ void jsonrpc_session_force_reconnect(struct jsonrpc_session *s) { reconnect_force_reconnect(s->reconnect, time_msec()); } +/* Sets 'max_backoff' as the maximum time, in milliseconds, to wait after a + * connection attempt fails before attempting to connect again. */ void jsonrpc_session_set_max_backoff(struct jsonrpc_session *s, int max_backoff) { reconnect_set_backoff(s->reconnect, 0, max_backoff); } +/* Sets the "probe interval" for 's' to 'probe_interval', in milliseconds. If + * this is zero, it disables the connection keepalive feature. Otherwise, if + * 's' is idle for 'probe_interval' milliseconds then 's' will send an echo + * request and, if no reply is received within an additional 'probe_interval' + * milliseconds, close the connection (then reconnect, if that feature is + * enabled). */ void jsonrpc_session_set_probe_interval(struct jsonrpc_session *s, int probe_interval) @@ -1127,9 +1150,11 @@ jsonrpc_session_set_probe_interval(struct jsonrpc_session *s, reconnect_set_probe_interval(s->reconnect, probe_interval); } +/* Sets the DSCP value used for 's''s connection to 'dscp'. If this is + * different from the DSCP value currently in use then the connection is closed + * and reconnected. */ void -jsonrpc_session_set_dscp(struct jsonrpc_session *s, - uint8_t dscp) +jsonrpc_session_set_dscp(struct jsonrpc_session *s, uint8_t dscp) { if (s->dscp != dscp) { pstream_close(s->pstream); -- cgit v1.2.1 From 8d66822447710e1f9a365cb2158a75ba8ad8cc36 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Tue, 31 Mar 2015 11:28:39 -0700 Subject: ovsdb-idl: Add function comments. Signed-off-by: Ben Pfaff Acked-by: Russell Bryant --- lib/ovsdb-idl.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/ovsdb-idl.c b/lib/ovsdb-idl.c index 9c25dbcbc..570f5cafa 100644 --- a/lib/ovsdb-idl.c +++ b/lib/ovsdb-idl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc. +/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -430,12 +430,16 @@ ovsdb_idl_verify_write_only(struct ovsdb_idl *idl) idl->verify_write_only = true; } +/* Returns true if 'idl' is currently connected or trying to connect. */ bool ovsdb_idl_is_alive(const struct ovsdb_idl *idl) { return jsonrpc_session_is_alive(idl->session); } +/* Returns the last error reported on a connection by 'idl'. The return value + * is 0 only if no connection made by 'idl' has ever encountered an error. See + * jsonrpc_get_status() for return value interpretation. */ int ovsdb_idl_get_last_error(const struct ovsdb_idl *idl) { -- cgit v1.2.1 From 5617ae6abe492498ee6350fe657a53e0ba21f8ba Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Sun, 29 Mar 2015 15:49:29 -0700 Subject: hmap: Don't include ovs-atomic.h unnecessarily. GNU C++ isn't too happy with ovs-atomic.h. We could fix that (maybe we should) but the report I received from a C++ user implied to me that it would be just as useful to just drop the unnecessary #include "ovs-atomic.h" from hmap.h. Reported-by: Michael Hu Signed-off-by: Ben Pfaff Acked-by: Jarno Rajahalme --- lib/cfm.c | 1 + lib/hmap.h | 3 +-- lib/lacp.c | 3 ++- lib/netdev-dummy.c | 3 ++- lib/ovs-lldp.h | 1 + 5 files changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/cfm.c b/lib/cfm.c index 380c5b06f..6a507a17d 100644 --- a/lib/cfm.c +++ b/lib/cfm.c @@ -29,6 +29,7 @@ #include "hash.h" #include "hmap.h" #include "netdev.h" +#include "ovs-atomic.h" #include "packets.h" #include "poll-loop.h" #include "random.h" diff --git a/lib/hmap.h b/lib/hmap.h index 85241f0e8..dc1e85ca5 100644 --- a/lib/hmap.h +++ b/lib/hmap.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009, 2010, 2012, 2013 Nicira, Inc. + * Copyright (c) 2008, 2009, 2010, 2012, 2013, 2015 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,7 +19,6 @@ #include #include -#include "ovs-atomic.h" #include "util.h" #ifdef __cplusplus diff --git a/lib/lacp.c b/lib/lacp.c index 6535e6dfe..65149fdb3 100644 --- a/lib/lacp.c +++ b/lib/lacp.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011, 2012, 2013, 2014 Nicira, Inc. +/* Copyright (c) 2011, 2012, 2013, 2014, 2015 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,6 +23,7 @@ #include "hash.h" #include "hmap.h" #include "dp-packet.h" +#include "ovs-atomic.h" #include "packets.h" #include "poll-loop.h" #include "seq.h" diff --git a/lib/netdev-dummy.c b/lib/netdev-dummy.c index 7fb103e6c..24c91c203 100644 --- a/lib/netdev-dummy.c +++ b/lib/netdev-dummy.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2011, 2012, 2013 Nicira, Inc. + * Copyright (c) 2010, 2011, 2012, 2013, 2015 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,6 +30,7 @@ #include "odp-util.h" #include "ofp-print.h" #include "ofpbuf.h" +#include "ovs-atomic.h" #include "packets.h" #include "pcap-file.h" #include "poll-loop.h" diff --git a/lib/ovs-lldp.h b/lib/ovs-lldp.h index 825096ba3..66288a577 100644 --- a/lib/ovs-lldp.h +++ b/lib/ovs-lldp.h @@ -24,6 +24,7 @@ #include "hmap.h" #include "list.h" #include "lldp/lldpd.h" +#include "ovs-atomic.h" #include "packets.h" #include "timer.h" -- cgit v1.2.1 From d314fc84e09301f485733fc9fc7c64ce781eb513 Mon Sep 17 00:00:00 2001 From: Alin Serdean Date: Tue, 31 Mar 2015 19:16:58 +0000 Subject: lockfile: Support \-delimited file names in lockfile_name(). Currently paths that have only forward slashes like the following "C:/package/binaries/conf.db" work seamlessly. If we try the native windows filepaths i.e. "C:\package\binaries\conf.db" we will hit the following problem: 2015-03-31T15:54:17Z|00001|lockfile|WARN|.c:\package\binaries\conf.db.~lock~: failed to open lock file: Invalid argument 2015-03-31T15:54:17Z|00002|lockfile|WARN|.c:\package\binaries\conf.db.~lock~: failed to lock file: Invalid argument ovsdb-server: I/O error: c:\package\binaries\conf.db: failed to lock lockfile (Invalid argument) In this patch we update the lockfile_name function to also look for backslashes, and also accommodate if we have a mix of backslashes and forward slashes. Signed-off-by: Alin Gabriel Serdean [blp@nicira.com simplified the code] Signed-off-by: Ben Pfaff --- lib/lockfile.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/lockfile.c b/lib/lockfile.c index 26aee3324..864d3eff0 100644 --- a/lib/lockfile.c +++ b/lib/lockfile.c @@ -82,6 +82,14 @@ lockfile_name(const char *filename_) * symlink, not one for each. */ filename = follow_symlinks(filename_); slash = strrchr(filename, '/'); + +#ifdef _WIN32 + char *backslash = strrchr(filename, '\\'); + if (backslash && (!slash || backslash > slash)) { + slash = backslash; + } +#endif + lockname = (slash ? xasprintf("%.*s/.%s.~lock~", (int) (slash - filename), filename, slash + 1) -- cgit v1.2.1 From da1e25d5af82d0d17fa9560cb8bb3a29afcd7818 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Tue, 31 Mar 2015 17:08:49 -0700 Subject: vswitch.xml: Improve description of forward-bpdu. The description was at best incomplete and difficult to understand. Reported-by: Brian Field Signed-off-by: Ben Pfaff Acked-by: Justin Pettit --- AUTHORS | 1 + vswitchd/vswitch.xml | 53 ++++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 42 insertions(+), 12 deletions(-) diff --git a/AUTHORS b/AUTHORS index 8fba915f5..1d2201c46 100644 --- a/AUTHORS +++ b/AUTHORS @@ -216,6 +216,7 @@ Brad Hall brad@nicira.com Brandon Heller brandonh@stanford.edu Brendan Kelley bkelley@nicira.com Brent Salisbury brent.salisbury@gmail.com +Brian Field Brian_Field@cable.comcast.com Bryan Fulton bryan@nicira.com Bryan Osoro bosoro@nicira.com Cedric Hobbs cedric@nicira.com diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml index 81e8b3f09..3256ce0a4 100644 --- a/vswitchd/vswitch.xml +++ b/vswitchd/vswitch.xml @@ -980,18 +980,47 @@ - Option to allow forwarding of BPDU frames when NORMAL action is - invoked. Frames with reserved Ethernet addresses (e.g. STP - BPDU) will be forwarded when this option is enabled and the - switch is not providing that functionality. If STP is enabled - on the port, STP BPDUs will never be forwarded. If the Open - vSwitch bridge is used to connect different Ethernet networks, - and if Open vSwitch node does not run STP, then this option - should be enabled. Default is disabled, set to - true to enable. - - The following destination MAC addresss will not be forwarded when this - option is enabled. + +

+ Controls forwarding of BPDUs and other network control frames when + NORMAL action is invoked. When this option is false or + unset, frames with reserved Ethernet addresses (see table below) will + not be forwarded. When this option is true, such frames + will not be treated specially. +

+ +

+ The above general rule has the following exceptions: +

+ +
    +
  • + If STP is enabled on the bridge (see the column in the table), the + bridge processes all received STP packets and never passes them to + OpenFlow or forwards them. This is true even if STP is disabled on + an individual port. +
  • + +
  • + If LLDP is enabled on an interface (see the column in the table), + the interface processes received LLDP packets and never passes them + to OpenFlow or forwards them. +
  • +
+ +

+ Set this option to true if the Open vSwitch bridge + connects different Ethernet networks and is not configured to + participate in STP. +

+ +

+ This option affects packets with the following destination MAC + addresses: +

+
01:80:c2:00:00:00
IEEE 802.1D Spanning Tree Protocol (STP).
-- cgit v1.2.1 From d18e52e3d97ee160b19a55927876423add24a13a Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Thu, 19 Mar 2015 23:45:42 -0700 Subject: ovsdb-idl: Tolerate missing tables and columns. Until now, if ovs-vsctl (or another client of the C ovsdb-idl library) was compiled against a schema that had a column or table that was not in the database actually being used (e.g. during an upgrade), and the column or table was selected for monitoring, then ovsdb-idl would fail to get any data at all because ovsdb-server would report an error due to a request about a column or a table it didn't know about. This commit fixes the problem by making ovsdb-idl retrieve the database schema from the database server and omit any tables or columns that don't exist from its monitoring request. This works OK for the kinds of upgrades that OVSDB otherwise supports gracefully because it will simply make the missing columns or tables appear empty, which clients of the ovsdb-idl library already have to tolerate. VMware-BZ: #1413562 Reported-by: Alex Wang Signed-off-by: Ben Pfaff Acked-by: Alex Wang --- lib/ovsdb-idl.c | 205 +++++++++++++++++++++++++++++++++++++++++------ lib/ovsdb-parser.c | 16 ++-- lib/ovsdb-parser.h | 5 +- tests/automake.mk | 2 +- tests/idltest2.ovsschema | 85 ++++++++++++++++++++ tests/ovsdb-idl.at | 75 +++++++++++++++++ 6 files changed, 357 insertions(+), 31 deletions(-) create mode 100644 tests/idltest2.ovsschema diff --git a/lib/ovsdb-idl.c b/lib/ovsdb-idl.c index 570f5cafa..4ec703240 100644 --- a/lib/ovsdb-idl.c +++ b/lib/ovsdb-idl.c @@ -28,11 +28,15 @@ #include "fatal-signal.h" #include "json.h" #include "jsonrpc.h" +#include "ovsdb/ovsdb.h" +#include "ovsdb/table.h" #include "ovsdb-data.h" #include "ovsdb-error.h" #include "ovsdb-idl-provider.h" +#include "ovsdb-parser.h" #include "poll-loop.h" #include "shash.h" +#include "sset.h" #include "util.h" #include "openvswitch/vlog.h" @@ -71,16 +75,25 @@ struct ovsdb_idl_arc { struct ovsdb_idl_row *dst; /* Destination row. */ }; +enum ovsdb_idl_state { + IDL_S_SCHEMA_REQUESTED, + IDL_S_MONITOR_REQUESTED, + IDL_S_MONITORING +}; + struct ovsdb_idl { const struct ovsdb_idl_class *class; struct jsonrpc_session *session; struct shash table_by_name; struct ovsdb_idl_table *tables; /* Contains "struct ovsdb_idl_table *"s.*/ - struct json *monitor_request_id; - unsigned int last_monitor_request_seqno; unsigned int change_seqno; bool verify_write_only; + /* Session state. */ + unsigned int state_seqno; + enum ovsdb_idl_state state; + struct json *request_id; + /* Database locking. */ char *lock_name; /* Name of lock we need, NULL if none. */ bool has_lock; /* Has db server told us we have the lock? */ @@ -124,7 +137,9 @@ static struct vlog_rate_limit syntax_rl = VLOG_RATE_LIMIT_INIT(1, 5); static struct vlog_rate_limit semantic_rl = VLOG_RATE_LIMIT_INIT(1, 5); static void ovsdb_idl_clear(struct ovsdb_idl *); -static void ovsdb_idl_send_monitor_request(struct ovsdb_idl *); +static void ovsdb_idl_send_schema_request(struct ovsdb_idl *); +static void ovsdb_idl_send_monitor_request(struct ovsdb_idl *, + const struct json *schema_json); static void ovsdb_idl_parse_update(struct ovsdb_idl *, const struct json *); static struct ovsdb_error *ovsdb_idl_parse_update__(struct ovsdb_idl *, const struct json *); @@ -214,7 +229,10 @@ ovsdb_idl_create(const char *remote, const struct ovsdb_idl_class *class, hmap_init(&table->rows); table->idl = idl; } - idl->last_monitor_request_seqno = UINT_MAX; + + idl->state_seqno = UINT_MAX; + idl->request_id = NULL; + hmap_init(&idl->outstanding_txns); return idl; @@ -239,7 +257,7 @@ ovsdb_idl_destroy(struct ovsdb_idl *idl) } shash_destroy(&idl->table_by_name); free(idl->tables); - json_destroy(idl->monitor_request_id); + json_destroy(idl->request_id); free(idl->lock_name); json_destroy(idl->lock_request_id); hmap_destroy(&idl->outstanding_txns); @@ -298,14 +316,17 @@ ovsdb_idl_run(struct ovsdb_idl *idl) unsigned int seqno; seqno = jsonrpc_session_get_seqno(idl->session); - if (idl->last_monitor_request_seqno != seqno) { - idl->last_monitor_request_seqno = seqno; + if (idl->state_seqno != seqno) { + idl->state_seqno = seqno; + json_destroy(idl->request_id); + idl->request_id = NULL; ovsdb_idl_txn_abort_all(idl); - ovsdb_idl_send_monitor_request(idl); + + ovsdb_idl_send_schema_request(idl); + idl->state = IDL_S_SCHEMA_REQUESTED; if (idl->lock_name) { ovsdb_idl_send_lock_request(idl); } - break; } msg = jsonrpc_session_recv(idl->session); @@ -321,14 +342,31 @@ ovsdb_idl_run(struct ovsdb_idl *idl) /* Database contents changed. */ ovsdb_idl_parse_update(idl, msg->params->u.array.elems[1]); } else if (msg->type == JSONRPC_REPLY - && idl->monitor_request_id - && json_equal(idl->monitor_request_id, msg->id)) { - /* Reply to our "monitor" request. */ - idl->change_seqno++; - json_destroy(idl->monitor_request_id); - idl->monitor_request_id = NULL; - ovsdb_idl_clear(idl); - ovsdb_idl_parse_update(idl, msg->result); + && idl->request_id + && json_equal(idl->request_id, msg->id)) { + switch (idl->state) { + case IDL_S_SCHEMA_REQUESTED: + /* Reply to our "get_schema" request. */ + json_destroy(idl->request_id); + idl->request_id = NULL; + ovsdb_idl_send_monitor_request(idl, msg->result); + idl->state = IDL_S_MONITOR_REQUESTED; + break; + + case IDL_S_MONITOR_REQUESTED: + /* Reply to our "monitor" request. */ + idl->change_seqno++; + json_destroy(idl->request_id); + idl->request_id = NULL; + idl->state = IDL_S_MONITORING; + ovsdb_idl_clear(idl); + ovsdb_idl_parse_update(idl, msg->result); + break; + + case IDL_S_MONITORING: + default: + OVS_NOT_REACHED(); + } } else if (msg->type == JSONRPC_REPLY && idl->lock_request_id && json_equal(idl->lock_request_id, msg->id)) { @@ -555,8 +593,107 @@ ovsdb_idl_omit(struct ovsdb_idl *idl, const struct ovsdb_idl_column *column) } static void -ovsdb_idl_send_monitor_request(struct ovsdb_idl *idl) +ovsdb_idl_send_schema_request(struct ovsdb_idl *idl) +{ + struct jsonrpc_msg *msg; + + json_destroy(idl->request_id); + msg = jsonrpc_create_request( + "get_schema", + json_array_create_1(json_string_create(idl->class->database)), + &idl->request_id); + jsonrpc_session_send(idl->session, msg); +} + +static void +log_error(struct ovsdb_error *error) +{ + char *s = ovsdb_error_to_string(error); + VLOG_WARN("error parsing database schema: %s", s); + free(s); + ovsdb_error_destroy(error); +} + +/* Frees 'schema', which is in the format returned by parse_schema(). */ +static void +free_schema(struct shash *schema) +{ + if (schema) { + struct shash_node *node, *next; + + SHASH_FOR_EACH_SAFE (node, next, schema) { + struct sset *sset = node->data; + sset_destroy(sset); + free(sset); + shash_delete(schema, node); + } + shash_destroy(schema); + free(schema); + } +} + +/* Parses 'schema_json', an OVSDB schema in JSON format as described in RFC + * 7047, to obtain the names of its rows and columns. If successful, returns + * an shash whose keys are table names and whose values are ssets, where each + * sset contains the names of its table's columns. On failure (due to a parse + * error), returns NULL. + * + * It would also be possible to use the general-purpose OVSDB schema parser in + * ovsdb-server, but that's overkill, possibly too strict for the current use + * case, and would require restructuring ovsdb-server to separate the schema + * code from the rest. */ +static struct shash * +parse_schema(const struct json *schema_json) +{ + struct ovsdb_parser parser; + const struct json *tables_json; + struct ovsdb_error *error; + struct shash_node *node; + struct shash *schema; + + ovsdb_parser_init(&parser, schema_json, "database schema"); + tables_json = ovsdb_parser_member(&parser, "tables", OP_OBJECT); + error = ovsdb_parser_destroy(&parser); + if (error) { + log_error(error); + return NULL; + } + + schema = xmalloc(sizeof *schema); + shash_init(schema); + SHASH_FOR_EACH (node, json_object(tables_json)) { + const char *table_name = node->name; + const struct json *json = node->data; + const struct json *columns_json; + + ovsdb_parser_init(&parser, json, "table schema for table %s", + table_name); + columns_json = ovsdb_parser_member(&parser, "columns", OP_OBJECT); + error = ovsdb_parser_destroy(&parser); + if (error) { + log_error(error); + free_schema(schema); + return NULL; + } + + struct sset *columns = xmalloc(sizeof *columns); + sset_init(columns); + + struct shash_node *node2; + SHASH_FOR_EACH (node2, json_object(columns_json)) { + const char *column_name = node2->name; + sset_add(columns, column_name); + } + shash_add(schema, table_name, columns); + } + return schema; +} + +static void +ovsdb_idl_send_monitor_request(struct ovsdb_idl *idl, + const struct json *schema_json) { + struct shash *schema = parse_schema(schema_json); struct json *monitor_requests; struct jsonrpc_msg *msg; size_t i; @@ -566,12 +703,25 @@ ovsdb_idl_send_monitor_request(struct ovsdb_idl *idl) const struct ovsdb_idl_table *table = &idl->tables[i]; const struct ovsdb_idl_table_class *tc = table->class; struct json *monitor_request, *columns; + const struct sset *table_schema; size_t j; + table_schema = (schema + ? shash_find_data(schema, table->class->name) + : NULL); + columns = table->need_table ? json_array_create_empty() : NULL; for (j = 0; j < tc->n_columns; j++) { const struct ovsdb_idl_column *column = &tc->columns[j]; if (table->modes[j] & OVSDB_IDL_MONITOR) { + if (table_schema + && !sset_contains(table_schema, column->name)) { + VLOG_WARN("%s table in %s database lacks %s column " + "(database needs upgrade?)", + table->class->name, idl->class->database, + column->name); + continue; + } if (!columns) { columns = json_array_create_empty(); } @@ -580,18 +730,27 @@ ovsdb_idl_send_monitor_request(struct ovsdb_idl *idl) } if (columns) { + if (schema && !table_schema) { + VLOG_WARN("%s database lacks %s table " + "(database needs upgrade?)", + idl->class->database, table->class->name); + json_destroy(columns); + continue; + } + monitor_request = json_object_create(); json_object_put(monitor_request, "columns", columns); json_object_put(monitor_requests, tc->name, monitor_request); } } + free_schema(schema); - json_destroy(idl->monitor_request_id); + json_destroy(idl->request_id); msg = jsonrpc_create_request( "monitor", json_array_create_3(json_string_create(idl->class->database), json_null_create(), monitor_requests), - &idl->monitor_request_id); + &idl->request_id); jsonrpc_session_send(idl->session, msg); } @@ -2389,11 +2548,11 @@ static void ovsdb_idl_update_has_lock(struct ovsdb_idl *idl, bool new_has_lock) { if (new_has_lock && !idl->has_lock) { - if (!idl->monitor_request_id) { + if (idl->state == IDL_S_MONITORING) { idl->change_seqno++; } else { - /* We're waiting for a monitor reply, so don't signal that the - * database changed. The monitor reply will increment change_seqno + /* We're setting up a session, so don't signal that the database + * changed. Finalizing the session will increment change_seqno * anyhow. */ } idl->is_lock_contended = false; diff --git a/lib/ovsdb-parser.c b/lib/ovsdb-parser.c index f4642ad01..3e448332b 100644 --- a/lib/ovsdb-parser.c +++ b/lib/ovsdb-parser.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, 2011, 2013 Nicira, Inc. +/* Copyright (c) 2009, 2011, 2013, 2015 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -126,6 +126,15 @@ ovsdb_parser_has_error(const struct ovsdb_parser *parser) return parser->error != NULL; } +struct ovsdb_error * +ovsdb_parser_destroy(struct ovsdb_parser *parser) +{ + free(parser->name); + sset_destroy(&parser->used); + + return parser->error; +} + struct ovsdb_error * ovsdb_parser_finish(struct ovsdb_parser *parser) { @@ -157,8 +166,5 @@ ovsdb_parser_finish(struct ovsdb_parser *parser) } } - free(parser->name); - sset_destroy(&parser->used); - - return parser->error; + return ovsdb_parser_destroy(parser); } diff --git a/lib/ovsdb-parser.h b/lib/ovsdb-parser.h index 8df9d5277..2f9f483d1 100644 --- a/lib/ovsdb-parser.h +++ b/lib/ovsdb-parser.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, 2010, 2011 Nicira, Inc. +/* Copyright (c) 2009, 2010, 2011, 2015 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -72,7 +72,8 @@ bool ovsdb_parser_has_error(const struct ovsdb_parser *); struct ovsdb_error *ovsdb_parser_get_error(const struct ovsdb_parser *); struct ovsdb_error *ovsdb_parser_finish(struct ovsdb_parser *) OVS_WARN_UNUSED_RESULT; -void ovsdb_parser_destroy(struct ovsdb_parser *); +struct ovsdb_error *ovsdb_parser_destroy(struct ovsdb_parser *) + OVS_WARN_UNUSED_RESULT; bool ovsdb_parser_is_id(const char *string); diff --git a/tests/automake.mk b/tests/automake.mk index abbfcb540..c691cf907 100644 --- a/tests/automake.mk +++ b/tests/automake.mk @@ -235,7 +235,7 @@ tests_test_lib_LDADD = lib/libopenvswitch.la # idltest schema and IDL OVSIDL_BUILT += tests/idltest.c tests/idltest.h tests/idltest.ovsidl IDLTEST_IDL_FILES = tests/idltest.ovsschema tests/idltest.ann -EXTRA_DIST += $(IDLTEST_IDL_FILES) +EXTRA_DIST += $(IDLTEST_IDL_FILES) tests/idltest2.ovsschema tests/idltest.ovsidl: $(IDLTEST_IDL_FILES) $(AM_V_GEN)$(OVSDB_IDLC) -C $(srcdir) annotate $(IDLTEST_IDL_FILES) > $@.tmp && \ mv $@.tmp $@ diff --git a/tests/idltest2.ovsschema b/tests/idltest2.ovsschema new file mode 100644 index 000000000..312c9cc9e --- /dev/null +++ b/tests/idltest2.ovsschema @@ -0,0 +1,85 @@ +{ + "name": "idltest", + "version": "1.2.3", + "tables": { + "link1": { + "columns": { + "i": { + "type": "integer" + }, + "k": { + "type": { + "key": { + "type": "uuid", + "refTable": "link1" + } + } + }, + "ka": { + "type": { + "key": { + "type": "uuid", + "refTable": "link1" + }, + "max": "unlimited", + "min": 0 + } + } + } + }, + "simple": { + "columns": { + "b": { + "type": "boolean" + }, + "ba": { + "type": { + "key": "boolean", + "max": 1, + "min": 0 + } + }, + "i": { + "type": "integer" + }, + "ia": { + "type": { + "key": "integer", + "max": "unlimited", + "min": 0 + } + }, + "r": { + "type": "real" + }, + "ra": { + "type": { + "key": "real", + "max": "unlimited", + "min": 0 + } + }, + "s": { + "type": "string" + }, + "sa": { + "type": { + "key": "string", + "max": "unlimited", + "min": 0 + } + }, + "u": { + "type": "uuid" + }, + "ua": { + "type": { + "key": "uuid", + "max": "unlimited", + "min": 0 + } + } + } + } + } +} diff --git a/tests/ovsdb-idl.at b/tests/ovsdb-idl.at index 89752f0f6..57642be68 100644 --- a/tests/ovsdb-idl.at +++ b/tests/ovsdb-idl.at @@ -496,3 +496,78 @@ OVSDB_CHECK_IDL_PY([getattr idl, insert ops], 002: i=2 k=2 ka=[] l2= uuid=<0> 003: done ]]) + +AT_SETUP([idl handling of missing tables and columns - C]) +AT_KEYWORDS([ovsdb server idl positive]) +OVS_RUNDIR=`pwd`; export OVS_RUNDIR + +# idltest2.ovsschema is the same as idltest.ovsschema, except that +# table link2 and column l2 have been deleted. But the IDL still +# expects them to be there, so this test checks that it properly +# tolerates them being missing. +AT_CHECK([ovsdb-tool create db $abs_srcdir/idltest2.ovsschema], + [0], [stdout], [ignore]) +AT_CHECK([ovsdb-server '-vPATTERN:console:ovsdb-server|%c|%m' --detach --no-chdir --pidfile="`pwd`"/pid --remote=punix:socket --unixctl="`pwd`"/unixctl db], [0], [ignore], [ignore]) +AT_CHECK([test-ovsdb '-vPATTERN:console:test-ovsdb|%c|%m' -vjsonrpc -t10 idl unix:socket ['["idltest", + {"op": "insert", + "table": "link1", + "row": {"i": 0, "k": ["named-uuid", "self"]}, + "uuid-name": "self"}]' \ + '["idltest", + {"op": "insert", + "table": "link1", + "row": {"i": 1, "k": ["named-uuid", "row2"]}, + "uuid-name": "row1"}, + {"op": "insert", + "table": "link1", + "row": {"i": 2, "k": ["named-uuid", "row1"]}, + "uuid-name": "row2"}]' \ + '["idltest", + {"op": "update", + "table": "link1", + "where": [["i", "==", 1]], + "row": {"k": ["uuid", "#1#"]}}]' \ + '["idltest", + {"op": "update", + "table": "link1", + "where": [], + "row": {"k": ["uuid", "#0#"]}}]']], + [0], [stdout], [stderr], [kill `cat pid`]) +AT_CHECK([sort stdout | ${PERL} $srcdir/uuidfilt.pl], [0], + [[000: empty +001: {"error":null,"result":[{"uuid":["uuid","<0>"]}]} +002: i=0 k=0 ka=[] l2= uuid=<0> +003: {"error":null,"result":[{"uuid":["uuid","<1>"]},{"uuid":["uuid","<2>"]}]} +004: i=0 k=0 ka=[] l2= uuid=<0> +004: i=1 k=2 ka=[] l2= uuid=<1> +004: i=2 k=1 ka=[] l2= uuid=<2> +005: {"error":null,"result":[{"count":1}]} +006: i=0 k=0 ka=[] l2= uuid=<0> +006: i=1 k=1 ka=[] l2= uuid=<1> +006: i=2 k=1 ka=[] l2= uuid=<2> +007: {"error":null,"result":[{"count":3}]} +008: i=0 k=0 ka=[] l2= uuid=<0> +008: i=1 k=0 ka=[] l2= uuid=<1> +008: i=2 k=0 ka=[] l2= uuid=<2> +009: done +]], [], [kill `cat pid`]) + +# Check that ovsdb-idl figured out that table link2 and column l2 are missing. +AT_CHECK([grep ovsdb_idl stderr | sort], [0], [dnl +test-ovsdb|ovsdb_idl|idltest database lacks link2 table (database needs upgrade?) +test-ovsdb|ovsdb_idl|link1 table in idltest database lacks l2 column (database needs upgrade?) +]) + +# Check that ovsdb-idl sent on "monitor" request and that it didn't +# mention that table or column, and (for paranoia) that it did mention another +# table and column. +AT_CHECK([grep -c '"monitor"' stderr], [0], [1 +]) +AT_CHECK([grep '"monitor"' stderr | grep link2], [1]) +AT_CHECK([grep '"monitor"' stderr | grep l2], [1]) +AT_CHECK([grep '"monitor"' stderr | grep -c '"link1"'], [0], [1 +]) +AT_CHECK([grep '"monitor"' stderr | grep -c '"ua"'], [0], [1 +]) +OVSDB_SERVER_SHUTDOWN +AT_CLEANUP -- cgit v1.2.1 From 508624b691e1517e4d426aa69165ea1efba80d53 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Thu, 19 Mar 2015 21:00:46 -0700 Subject: ovsdb-server: Correct malformed error replies to certain JSON-RPC requests. I realized that this bug existed only a few weeks ago, but it has been there since the earliest ovsdb-server code. Signed-off-by: Ben Pfaff Acked-by: Alex Wang --- ovsdb/jsonrpc-server.c | 26 ++++++++++++++------------ ovsdb/ovsdb-server.1.in | 29 ++++++++++++++++++++++++++++- tests/ovsdb-server.at | 2 +- 3 files changed, 43 insertions(+), 14 deletions(-) diff --git a/ovsdb/jsonrpc-server.c b/ovsdb/jsonrpc-server.c index 2ba5ddd45..95b49958f 100644 --- a/ovsdb/jsonrpc-server.c +++ b/ovsdb/jsonrpc-server.c @@ -78,8 +78,9 @@ static void ovsdb_jsonrpc_trigger_complete_done( struct ovsdb_jsonrpc_session *); /* Monitors. */ -static struct json *ovsdb_jsonrpc_monitor_create( - struct ovsdb_jsonrpc_session *, struct ovsdb *, struct json *params); +static struct jsonrpc_msg *ovsdb_jsonrpc_monitor_create( + struct ovsdb_jsonrpc_session *, struct ovsdb *, struct json *params, + const struct json *request_id); static struct jsonrpc_msg *ovsdb_jsonrpc_monitor_cancel( struct ovsdb_jsonrpc_session *, struct json_array *params, @@ -674,7 +675,7 @@ ovsdb_jsonrpc_lookup_db(const struct ovsdb_jsonrpc_session *s, return db; error: - *replyp = jsonrpc_create_reply(ovsdb_error_to_json(error), request->id); + *replyp = jsonrpc_create_error(ovsdb_error_to_json(error), request->id); ovsdb_error_destroy(error); return NULL; } @@ -752,7 +753,7 @@ ovsdb_jsonrpc_session_lock(struct ovsdb_jsonrpc_session *s, return jsonrpc_create_reply(result, request->id); error: - reply = jsonrpc_create_reply(ovsdb_error_to_json(error), request->id); + reply = jsonrpc_create_error(ovsdb_error_to_json(error), request->id); ovsdb_error_destroy(error); return reply; } @@ -812,7 +813,7 @@ ovsdb_jsonrpc_session_unlock(struct ovsdb_jsonrpc_session *s, return jsonrpc_create_reply(json_object_create(), request->id); error: - reply = jsonrpc_create_reply(ovsdb_error_to_json(error), request->id); + reply = jsonrpc_create_error(ovsdb_error_to_json(error), request->id); ovsdb_error_destroy(error); return reply; } @@ -842,9 +843,8 @@ ovsdb_jsonrpc_session_got_request(struct ovsdb_jsonrpc_session *s, } else if (!strcmp(request->method, "monitor")) { struct ovsdb *db = ovsdb_jsonrpc_lookup_db(s, request, &reply); if (!reply) { - reply = jsonrpc_create_reply( - ovsdb_jsonrpc_monitor_create(s, db, request->params), - request->id); + reply = ovsdb_jsonrpc_monitor_create(s, db, request->params, + request->id); } } else if (!strcmp(request->method, "monitor_cancel")) { reply = ovsdb_jsonrpc_monitor_cancel(s, json_array(request->params), @@ -1221,9 +1221,10 @@ ovsdb_jsonrpc_parse_monitor_request(struct ovsdb_jsonrpc_monitor_table *mt, return NULL; } -static struct json * +static struct jsonrpc_msg * ovsdb_jsonrpc_monitor_create(struct ovsdb_jsonrpc_session *s, struct ovsdb *db, - struct json *params) + struct json *params, + const struct json *request_id) { struct ovsdb_jsonrpc_monitor *m = NULL; struct json *monitor_id, *monitor_requests; @@ -1310,7 +1311,8 @@ ovsdb_jsonrpc_monitor_create(struct ovsdb_jsonrpc_session *s, struct ovsdb *db, } } - return ovsdb_jsonrpc_monitor_get_initial(m); + return jsonrpc_create_reply(ovsdb_jsonrpc_monitor_get_initial(m), + request_id); error: if (m) { @@ -1319,7 +1321,7 @@ error: json = ovsdb_error_to_json(error); ovsdb_error_destroy(error); - return json; + return jsonrpc_create_error(json, request_id); } static struct jsonrpc_msg * diff --git a/ovsdb/ovsdb-server.1.in b/ovsdb/ovsdb-server.1.in index 0fafc49a9..e33d718cb 100644 --- a/ovsdb/ovsdb-server.1.in +++ b/ovsdb/ovsdb-server.1.in @@ -251,7 +251,34 @@ vSwitch 2.4 and later extend to allow the use of \fB<\fR, of 0 or 1 integer'' and ``set of 0 or 1 real''. These conditions evaluate to false when the column is empty, and otherwise as described in RFC 7047 for integer and real types. - +. +.SH "BUGS" +. +In Open vSwitch before version 2.4, when \fBovsdb\-server\fR sent +JSON-RPC error responses to some requests, it incorrectly formulated +them with the \fBresult\fR and \fBerror\fR swapped, so that the +response appeared to indicate success (with a nonsensical result) +rather than an error. The requests that suffered from this problem +were: +. +.IP \fBtransact\fR +.IQ \fBget_schema\fR +Only if the request names a nonexistent database. +.IP \fBmonitor\fR +.IQ \fBlock\fR +.IQ \fBunlock\fR +In all error cases. +. +.PP +Of these cases, the only error that a well-written application is +likely to encounter in practice is \fBmonitor\fR of tables or columns +that do not exist, in an situation where the application has been +upgraded but the old database schema is still temporarily in use. To +handle this situation gracefully, we recommend that clients should +treat a \fBmonitor\fR response with a \fBresult\fR that contains an +\fBerror\fR key-value pair as an error (assuming that the database +being monitored does not contain a table named \fBerror\fR). +. .SH "SEE ALSO" . .BR ovsdb\-tool (1). diff --git a/tests/ovsdb-server.at b/tests/ovsdb-server.at index 35f0d118d..c9ce4b1fd 100644 --- a/tests/ovsdb-server.at +++ b/tests/ovsdb-server.at @@ -163,7 +163,7 @@ ordinals ], [ignore], [test ! -e pid || kill `cat pid`]) AT_CHECK( [[ovstest test-jsonrpc request unix:socket get_schema [\"nonexistent\"]]], [0], - [[{"error":null,"id":0,"result":{"details":"get_schema request specifies unknown database nonexistent","error":"unknown database","syntax":"[\"nonexistent\"]"}} + [[{"error":{"details":"get_schema request specifies unknown database nonexistent","error":"unknown database","syntax":"[\"nonexistent\"]"},"id":0,"result":null} ]], [], [test ! -e pid || kill `cat pid`]) OVSDB_SERVER_SHUTDOWN AT_CLEANUP -- cgit v1.2.1 From b3cceba0b7c4013f46b01f8987e8716d7857c6db Mon Sep 17 00:00:00 2001 From: Alex Wang Date: Wed, 1 Apr 2015 16:11:19 -0700 Subject: bridge: Execute bridge_run() only after retrieving db contents. During upgrade of ovs-vswitchd, we do not want to recreate the already configured kernel interfaces. Especially when IP address is assigned to the internal port, the recreation will cause the lost of connection. Therefore, ovs-vswitchd should read current ovsdb content first and then reuse the existing kernel interfaces that are configured in ovsdb. In terms of the code language, ovs-vswitchd should only execute bridge_run() after it finishes reading the ovsdb content. However, this expected behavior is broken by the recent commit d18e52e (ovsdb-idl: Tolerate missing tables and columns.) which causes the execution of bridge_run() before getting the hint of configured interfaces from ovsdb. To fix the issue, this commit makes sure that the execution of bridge_run() happens only after retrieving the ovsdb contents. VMware-BZ: #1424342 Signed-off-by: Alex Wang Acked-by: Ben Pfaff --- vswitchd/bridge.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index 2e90ea22c..afd7c3e66 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -2895,7 +2895,10 @@ bridge_run(void) * disable system stats collection. */ system_stats_enable(false); return; - } else if (!ovsdb_idl_has_lock(idl)) { + } else if (!ovsdb_idl_has_lock(idl) + || !ovsdb_idl_has_ever_connected(idl)) { + /* Returns if not holding the lock or not done retrieving db + * contents. */ return; } cfg = ovsrec_open_vswitch_first(idl); -- cgit v1.2.1 From 190cf5338956c53596f60b20fa7672ba052ee815 Mon Sep 17 00:00:00 2001 From: Sorin Vinturis Date: Thu, 2 Apr 2015 19:35:32 +0000 Subject: datapath-windows: Make GET_PID a separate IOCTL Added a new IOCTL in order to retrieve the PID from the kernel datapath. The new method uses a direct and cleaner way, as opposed to the old way of using a Netlink transaction, avoiding the unnecessary overhead. Signed-off-by: Sorin Vinturis Reported-by: Alin Gabriel Serdean Reported-at: https://github.com/openvswitch/ovs-issues/issues/31 Acked-by: Nithin Raju Acked-by: Alin Gabriel Serdean Tested-by: Alin Gabriel Serdean Signed-off-by: Ben Pfaff --- datapath-windows/include/OvsDpInterfaceExt.h | 18 ++++---- datapath-windows/ovsext/Datapath.c | 63 +++++++++++++++------------- datapath-windows/ovsext/Flow.c | 2 +- lib/netlink-socket.c | 56 +++++-------------------- 4 files changed, 57 insertions(+), 82 deletions(-) diff --git a/datapath-windows/include/OvsDpInterfaceExt.h b/datapath-windows/include/OvsDpInterfaceExt.h index 7e09caf77..e2353767d 100644 --- a/datapath-windows/include/OvsDpInterfaceExt.h +++ b/datapath-windows/include/OvsDpInterfaceExt.h @@ -29,22 +29,27 @@ #define OVS_IOCTL_DEVICE_TYPE 45000 -/* We used Direct I/O (zero copy) for the buffers. */ #define OVS_IOCTL_START 0x100 +/* We used Direct I/O (zero copy) for the buffers. */ +/* Non-Netlink-based IOCTLs. */ +#define OVS_IOCTL_GET_PID \ + CTL_CODE (OVS_IOCTL_DEVICE_TYPE, OVS_IOCTL_START + 0x0, METHOD_BUFFERED,\ + FILE_WRITE_ACCESS) +/* Netlink-based IOCTLs. */ #define OVS_IOCTL_READ \ - CTL_CODE (OVS_IOCTL_DEVICE_TYPE, OVS_IOCTL_START + 0x0, METHOD_OUT_DIRECT,\ + CTL_CODE (OVS_IOCTL_DEVICE_TYPE, OVS_IOCTL_START + 0x1, METHOD_OUT_DIRECT,\ FILE_READ_ACCESS) #define OVS_IOCTL_READ_EVENT \ - CTL_CODE (OVS_IOCTL_DEVICE_TYPE, OVS_IOCTL_START + 0x1, METHOD_OUT_DIRECT, \ + CTL_CODE (OVS_IOCTL_DEVICE_TYPE, OVS_IOCTL_START + 0x2, METHOD_OUT_DIRECT, \ FILE_READ_ACCESS) #define OVS_IOCTL_READ_PACKET \ - CTL_CODE (OVS_IOCTL_DEVICE_TYPE, OVS_IOCTL_START + 0x2, METHOD_OUT_DIRECT, \ + CTL_CODE (OVS_IOCTL_DEVICE_TYPE, OVS_IOCTL_START + 0x3, METHOD_OUT_DIRECT, \ FILE_READ_ACCESS) #define OVS_IOCTL_WRITE \ - CTL_CODE (OVS_IOCTL_DEVICE_TYPE, OVS_IOCTL_START + 0x3, METHOD_IN_DIRECT,\ + CTL_CODE (OVS_IOCTL_DEVICE_TYPE, OVS_IOCTL_START + 0x4, METHOD_IN_DIRECT,\ FILE_READ_ACCESS) #define OVS_IOCTL_TRANSACT \ - CTL_CODE (OVS_IOCTL_DEVICE_TYPE, OVS_IOCTL_START + 0x4, METHOD_OUT_DIRECT,\ + CTL_CODE (OVS_IOCTL_DEVICE_TYPE, OVS_IOCTL_START + 0x5, METHOD_OUT_DIRECT,\ FILE_WRITE_ACCESS) /* @@ -75,7 +80,6 @@ /* Commands available under the OVS_WIN_CONTROL_FAMILY. */ enum ovs_win_control_cmd { - OVS_CTRL_CMD_WIN_GET_PID, OVS_CTRL_CMD_WIN_PEND_REQ, OVS_CTRL_CMD_WIN_PEND_PACKET_REQ, OVS_CTRL_CMD_MC_SUBSCRIBE_REQ, diff --git a/datapath-windows/ovsext/Datapath.c b/datapath-windows/ovsext/Datapath.c index 888c6ef79..e566ea9d0 100644 --- a/datapath-windows/ovsext/Datapath.c +++ b/datapath-windows/ovsext/Datapath.c @@ -87,8 +87,7 @@ typedef struct _NETLINK_FAMILY { } NETLINK_FAMILY, *PNETLINK_FAMILY; /* Handlers for the various netlink commands. */ -static NetlinkCmdHandler OvsGetPidCmdHandler, - OvsPendEventCmdHandler, +static NetlinkCmdHandler OvsPendEventCmdHandler, OvsPendPacketCmdHandler, OvsSubscribeEventCmdHandler, OvsSubscribePacketCmdHandler, @@ -110,6 +109,8 @@ static NTSTATUS HandleGetDpDump(POVS_USER_PARAMS_CONTEXT usrParamsCtx, UINT32 *replyLen); static NTSTATUS HandleDpTransactionCommon( POVS_USER_PARAMS_CONTEXT usrParamsCtx, UINT32 *replyLen); +static NTSTATUS OvsGetPidHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx, + UINT32 *replyLen); /* * The various netlink families, along with the supported commands. Most of @@ -120,11 +121,6 @@ static NTSTATUS HandleDpTransactionCommon( /* Netlink control family: this is a Windows specific family. */ NETLINK_CMD nlControlFamilyCmdOps[] = { - { .cmd = OVS_CTRL_CMD_WIN_GET_PID, - .handler = OvsGetPidCmdHandler, - .supportedDevOp = OVS_TRANSACTION_DEV_OP, - .validateDpIndex = FALSE, - }, { .cmd = OVS_CTRL_CMD_WIN_PEND_REQ, .handler = OvsPendEventCmdHandler, .supportedDevOp = OVS_WRITE_DEV_OP, @@ -736,6 +732,24 @@ OvsDeviceControl(PDEVICE_OBJECT deviceObject, * operation. */ switch (code) { + case OVS_IOCTL_GET_PID: + /* Both input buffer and output buffer use the same location. */ + outputBuffer = irp->AssociatedIrp.SystemBuffer; + if (outputBufferLen != 0) { + InitUserParamsCtx(irp, instance, 0, NULL, + inputBuffer, inputBufferLen, + outputBuffer, outputBufferLen, + &usrParamsCtx); + + ASSERT(outputBuffer); + } else { + status = STATUS_NDIS_INVALID_LENGTH; + goto done; + } + + status = OvsGetPidHandler(&usrParamsCtx, &replyLen); + goto done; + case OVS_IOCTL_TRANSACT: /* Both input buffer and output buffer are mandatory. */ if (outputBufferLen != 0) { @@ -947,11 +961,9 @@ ValidateNetlinkCmd(UINT32 devOp, } /* Validate the PID. */ - if (ovsMsg->genlMsg.cmd != OVS_CTRL_CMD_WIN_GET_PID) { - if (ovsMsg->nlMsg.nlmsgPid != instance->pid) { - status = STATUS_INVALID_PARAMETER; - goto done; - } + if (ovsMsg->nlMsg.nlmsgPid != instance->pid) { + status = STATUS_INVALID_PARAMETER; + goto done; } status = STATUS_SUCCESS; @@ -992,38 +1004,33 @@ InvokeNetlinkCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx, /* * -------------------------------------------------------------------------- - * Command Handler for 'OVS_CTRL_CMD_WIN_GET_PID'. + * Handler for 'OVS_IOCTL_GET_PID'. * * Each handle on the device is assigned a unique PID when the handle is - * created. On platforms that support netlink natively, the PID is available - * to userspace when the netlink socket is created. However, without native - * netlink support on Windows, OVS datapath generates the PID and lets the - * userspace query it. - * - * This function implements the query. + * created. This function passes the PID to userspace using METHOD_BUFFERED + * method. * -------------------------------------------------------------------------- */ static NTSTATUS -OvsGetPidCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx, - UINT32 *replyLen) +OvsGetPidHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx, + UINT32 *replyLen) { - POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer; - POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer; + NTSTATUS status = STATUS_SUCCESS; + PUINT32 msgOut = (PUINT32)usrParamsCtx->outputBuffer; if (usrParamsCtx->outputLength >= sizeof *msgOut) { POVS_OPEN_INSTANCE instance = (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance; RtlZeroMemory(msgOut, sizeof *msgOut); - msgOut->nlMsg.nlmsgSeq = msgIn->nlMsg.nlmsgSeq; - msgOut->nlMsg.nlmsgPid = instance->pid; + RtlCopyMemory(msgOut, &instance->pid, sizeof(*msgOut)); *replyLen = sizeof *msgOut; - /* XXX: We might need to return the DP index as well. */ } else { - return STATUS_NDIS_INVALID_LENGTH; + *replyLen = sizeof *msgOut; + status = STATUS_NDIS_INVALID_LENGTH; } - return STATUS_SUCCESS; + return status; } /* diff --git a/datapath-windows/ovsext/Flow.c b/datapath-windows/ovsext/Flow.c index 97220b468..f25fe9a4f 100644 --- a/datapath-windows/ovsext/Flow.c +++ b/datapath-windows/ovsext/Flow.c @@ -319,7 +319,7 @@ OvsFlowNlCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx, rc = OvsPutFlowIoctl(&mappedFlow, sizeof (struct OvsFlowPut), &stats); if (rc != STATUS_SUCCESS) { - OVS_LOG_ERROR("OvsFlowPut failed."); + OVS_LOG_ERROR("OvsPutFlowIoctl failed."); goto done; } diff --git a/lib/netlink-socket.c b/lib/netlink-socket.c index df889d3eb..fab2a6681 100644 --- a/lib/netlink-socket.c +++ b/lib/netlink-socket.c @@ -273,63 +273,27 @@ nl_sock_destroy(struct nl_sock *sock) #ifdef _WIN32 /* Reads the pid for 'sock' generated in the kernel datapath. The function - * follows a transaction semantic. Eventually this function should call into - * nl_transact. */ + * uses a separate IOCTL instead of a transaction semantic to avoid unnecessary + * message overhead. */ static int get_sock_pid_from_kernel(struct nl_sock *sock) { - struct nl_transaction txn; - struct ofpbuf request; - uint64_t request_stub[128]; - struct ofpbuf reply; - uint64_t reply_stub[128]; - struct ovs_header *ovs_header; - struct nlmsghdr *nlmsg; - uint32_t seq; - int retval; - DWORD bytes; - int ovs_msg_size = sizeof (struct nlmsghdr) + sizeof (struct genlmsghdr) + - sizeof (struct ovs_header); - - ofpbuf_use_stub(&request, request_stub, sizeof request_stub); - txn.request = &request; - ofpbuf_use_stub(&reply, reply_stub, sizeof reply_stub); - txn.reply = &reply; - - seq = nl_sock_allocate_seq(sock, 1); - nl_msg_put_genlmsghdr(&request, 0, OVS_WIN_NL_CTRL_FAMILY_ID, 0, - OVS_CTRL_CMD_WIN_GET_PID, OVS_WIN_CONTROL_VERSION); - nlmsg = nl_msg_nlmsghdr(txn.request); - nlmsg->nlmsg_seq = seq; - - ovs_header = ofpbuf_put_uninit(&request, sizeof *ovs_header); - ovs_header->dp_ifindex = 0; - ovs_header = ofpbuf_put_uninit(&reply, ovs_msg_size); + uint32_t pid = 0; + int retval = 0; + DWORD bytes = 0; - if (!DeviceIoControl(sock->handle, OVS_IOCTL_TRANSACT, - txn.request->data, txn.request->size, - txn.reply->data, txn.reply->size, + if (!DeviceIoControl(sock->handle, OVS_IOCTL_GET_PID, + NULL, 0, &pid, sizeof(pid), &bytes, NULL)) { retval = EINVAL; - goto done; } else { - if (bytes < ovs_msg_size) { + if (bytes < sizeof(pid)) { retval = EINVAL; - goto done; - } - - nlmsg = nl_msg_nlmsghdr(txn.reply); - if (nlmsg->nlmsg_seq != seq) { - retval = EINVAL; - goto done; + } else { + sock->pid = pid; } - sock->pid = nlmsg->nlmsg_pid; } - retval = 0; -done: - ofpbuf_uninit(&request); - ofpbuf_uninit(&reply); return retval; } #endif /* _WIN32 */ -- cgit v1.2.1 From 73c33892acabe104ddd3d87561d368f3b75d3047 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Thu, 2 Apr 2015 09:52:03 -0700 Subject: INSTALL.md: Document how to add custom compiler flags. CC: Mark B Kavanagh Signed-off-by: Ben Pfaff Acked-by: Russell Bryant --- INSTALL.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/INSTALL.md b/INSTALL.md index 3762e0054..d06017157 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -196,6 +196,14 @@ To use 'clang' compiler: `% ./configure CC=clang` +To supply special flags to the C compiler, specify them as CFLAGS on +the configure command line. If you want the default CFLAGS, which +include "-g" to build debug symbols and "-O2" to enable optimizations, +you must include them yourself. For example, to build with the +default CFLAGS plus "-mssse3", you might run configure as follows: + + `% ./configure CFLAGS="-g -O2 -mssse3"` + To build the Linux kernel module, so that you can run the kernel-based switch, pass the location of the kernel build directory on --with-linux. For example, to build for a running -- cgit v1.2.1 From 97447f55a9678739a64d10db9401858cf040abcf Mon Sep 17 00:00:00 2001 From: Daniele Di Proietto Date: Wed, 1 Apr 2015 17:20:57 +0100 Subject: dpif-netdev: Remove support for DPIF_FP_ZERO_STATS flag Since flow statistics are thread local and updated without any lock, it is not correct to do a memset from another thread. This commit simply removes the support for the flag. It is not needed by ofproto-dpif, it is only exposed by dpctl commands. Signed-off-by: Daniele Di Proietto Acked-by: Ethan Jackson --- lib/dpif-netdev.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 6b61db4b6..15bc7f932 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -1842,7 +1842,16 @@ dpif_netdev_flow_put(struct dpif *dpif, const struct dpif_flow_put *put) get_dpif_flow_stats(netdev_flow, put->stats); } if (put->flags & DPIF_FP_ZERO_STATS) { - memset(&netdev_flow->stats, 0, sizeof netdev_flow->stats); + /* XXX: The userspace datapath uses thread local statistics + * (for flows), which should be updated only by the owning + * thread. Since we cannot write on stats memory here, + * we choose not to support this flag. Please note: + * - This feature is currently used only by dpctl commands with + * option --clear. + * - Should the need arise, this operation can be implemented + * by keeping a base value (to be update here) for each + * counter, and subtracting it before outputting the stats */ + error = EOPNOTSUPP; } ovsrcu_postpone(dp_netdev_actions_free, old_actions); -- cgit v1.2.1 From 4f7e5c274bfff6187313588a66491bcf45b7a709 Mon Sep 17 00:00:00 2001 From: Russell Bryant Date: Thu, 2 Apr 2015 17:51:49 -0400 Subject: INSTALL.md: Add note about EXTRA_CFLAGS. Add a note about the use of EXTRA_CFLAGS to provide custom CFLAGS for the build of the Linux kernel module. This addition is technically in the "configuring the sources" section of the document. However, it's the spot where custom CFLAGS is discussed already, so that seemed like the best place to put it. Alternatively, it could go in the "Building the Sources" section instead. Signed-off-by: Russell Bryant Signed-off-by: Ben Pfaff --- INSTALL.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/INSTALL.md b/INSTALL.md index d06017157..81568987d 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -204,6 +204,12 @@ default CFLAGS plus "-mssse3", you might run configure as follows: `% ./configure CFLAGS="-g -O2 -mssse3"` +Note that these CFLAGS are not applied when building the Linux +kernel module. Custom CFLAGS for the kernel module are supplied +using the EXTRA_CFLAGS variable when running make. So, for example: + + `% make EXTRA_CFLAGS="-Wno-error=date-time" + To build the Linux kernel module, so that you can run the kernel-based switch, pass the location of the kernel build directory on --with-linux. For example, to build for a running -- cgit v1.2.1 From 416e71322f82beea869b2e5928be5ae60f2577de Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Fri, 3 Apr 2015 15:10:57 -0700 Subject: acinclude: Always assume buggy strtok_r() for glibc < 2.8. Lately our internal build system has been seeing intermittent failures that I can't explain. With old glibc versions, the "configure" time check will pass, but the equivalent (almost identical) "make check" test will fail. One possibility, I guess, is that occasionally address space randomization will put valid data at the 0xc0ffee address that the test assumes will segfault, and another is that some change in compiler optimization flags is making a difference. At any rate, I think it's safe to just always assume that this strtok_r() bug is present whenever glibc before 2.8 is in use. Specifically we've seen this happen intermittently when building against the XenServer DDK 5.6.100 build 39265, which uses glibc 2.5. Reported-by: Alex Wang Signed-off-by: Ben Pfaff Acked-by: Alex Wang --- acinclude.m4 | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/acinclude.m4 b/acinclude.m4 index 479da2e2e..b09f2f258 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -1,6 +1,6 @@ # -*- autoconf -*- -# Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc. +# Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -494,7 +494,13 @@ AC_DEFUN([OVS_CHECK_STRTOK_R], [AC_LANG_PROGRAM([#include #include ], - [[char string[] = ":::"; + [[#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 + /* Assume bug is present, because relatively minor + changes in compiler settings (e.g. optimization + level) can make it crop up. */ + return 1; + #else + char string[] = ":::"; char *save_ptr = (char *) 0xc0ffee; char *token1, *token2; token1 = strtok_r(string, ":", &save_ptr); @@ -502,6 +508,7 @@ AC_DEFUN([OVS_CHECK_STRTOK_R], freopen ("/dev/null", "w", stdout); printf ("%s %s\n", token1, token2); return 0; + #endif ]])], [ovs_cv_strtok_r_bug=no], [ovs_cv_strtok_r_bug=yes], -- cgit v1.2.1 From 5a38795f5e6623b39004b53c7fede08399a09d79 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Sat, 4 Apr 2015 08:24:13 +0200 Subject: datapath: Turn vports with dependencies into separate modules Upstream commit: The internal and netdev vport remain part of openvswitch.ko. Encap vports including vxlan, gre, and geneve can be built as separate modules and are loaded on demand. Modules can be unloaded after use. Datapath ports keep a reference to the vport module during their lifetime. Allows to remove the error prone maintenance of the global list vport_ops_list. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller Also folds in the follow-up commits 9ba559d9ca3 to turned the non-GPL symbol exports to GPL exports, and fa2d8ff4e35 which fixes a module reference release bug. Exports various backwards compat functions linked into the main openvswitch module as GPL symbols to ensure vport modules can use them. Some fiddling with the Makefile was needed to work around the fact that Makefile variables can't contain '-' characters needed to define 'vport-xxx' module sources. Also, Kbuild complains heavily if a $(module)-y = $(module).o is defined which is actually backed with a .c file of the same name. Therefore, a new $(build_multi_modules) variable is defined which lists all module which consist of more than one source file. Upstream: 62b9c8d0372 ("ovs: Turn vports with dependencies into separate modules") Upstream: 9ba559d9ca3 ("openvswitch: Export symbols as GPL symbols.") Upstream: fa2d8ff4e35 ("openvswitch: Return vport module ref before destruction") Signed-off-by: Thomas Graf Acked-by: Pravin B Shelar --- datapath/Modules.mk | 20 +++++-- datapath/datapath.c | 17 +++++- datapath/linux/Kbuild.in | 4 +- datapath/linux/compat/flow_dissector.c | 1 + datapath/linux/compat/geneve.c | 3 + datapath/linux/compat/gre.c | 4 ++ datapath/linux/compat/ip_tunnels_core.c | 4 ++ datapath/linux/compat/udp_tunnel.c | 6 ++ datapath/linux/compat/vxlan.c | 3 + datapath/vport-geneve.c | 22 ++++++- datapath/vport-gre.c | 39 ++++++++++++- datapath/vport-internal_dev.c | 17 +++++- datapath/vport-lisp.c | 22 ++++++- datapath/vport-netdev.c | 13 ++++- datapath/vport-netdev.h | 3 + datapath/vport-vxlan.c | 23 +++++++- datapath/vport.c | 100 ++++++++++++++++++++++---------- datapath/vport.h | 16 ++--- 18 files changed, 259 insertions(+), 58 deletions(-) diff --git a/datapath/Modules.mk b/datapath/Modules.mk index 33f9dd9b5..e9f40797e 100644 --- a/datapath/Modules.mk +++ b/datapath/Modules.mk @@ -2,7 +2,14 @@ # # Some modules should be built but not distributed, e.g. third-party # hwtable modules. -both_modules = openvswitch +build_multi_modules = \ + openvswitch +both_modules = \ + $(build_multi_modules) \ + vport_geneve \ + vport_gre \ + vport_lisp \ + vport_vxlan build_modules = $(both_modules) # Modules to build dist_modules = $(both_modules) # Modules to distribute @@ -14,12 +21,13 @@ openvswitch_sources = \ flow_netlink.c \ flow_table.c \ vport.c \ - vport-geneve.c \ - vport-gre.c \ vport-internal_dev.c \ - vport-lisp.c \ - vport-netdev.c \ - vport-vxlan.c + vport-netdev.c + +vport_geneve_sources = vport-geneve.c +vport_vxlan_sources = vport-vxlan.c +vport_gre_sources = vport-gre.c +vport_lisp_sources = vport-lisp.c openvswitch_headers = \ compat.h \ diff --git a/datapath/datapath.c b/datapath/datapath.c index 7f431ed8e..c0af9ad09 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -61,6 +61,7 @@ #include "vport-netdev.h" int ovs_net_id __read_mostly; +EXPORT_SYMBOL_GPL(ovs_net_id); static struct genl_family dp_packet_genl_family; static struct genl_family dp_flow_genl_family; @@ -134,6 +135,7 @@ int lockdep_ovsl_is_held(void) else return 1; } +EXPORT_SYMBOL_GPL(lockdep_ovsl_is_held); #endif static int queue_gso_packets(struct datapath *dp, struct sk_buff *, @@ -1900,6 +1902,7 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info) return -ENOMEM; ovs_lock(); +restart: dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); err = -ENODEV; if (!dp) @@ -1931,8 +1934,11 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info) vport = new_vport(&parms); err = PTR_ERR(vport); - if (IS_ERR(vport)) + if (IS_ERR(vport)) { + if (err == -EAGAIN) + goto restart; goto exit_unlock_free; + } err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid, info->snd_seq, 0, OVS_VPORT_CMD_NEW); @@ -2291,12 +2297,18 @@ static int __init dp_init(void) if (err) goto error_netns_exit; + err = ovs_netdev_init(); + if (err) + goto error_unreg_notifier; + err = dp_register_genl(); if (err < 0) - goto error_unreg_notifier; + goto error_unreg_netdev; return 0; +error_unreg_netdev: + ovs_netdev_exit(); error_unreg_notifier: unregister_netdevice_notifier(&ovs_dp_device_notifier); error_netns_exit: @@ -2316,6 +2328,7 @@ error: static void dp_cleanup(void) { dp_unregister_genl(ARRAY_SIZE(dp_genl_families)); + ovs_netdev_exit(); unregister_netdevice_notifier(&ovs_dp_device_notifier); unregister_pernet_device(&ovs_net_ops); rcu_barrier(); diff --git a/datapath/linux/Kbuild.in b/datapath/linux/Kbuild.in index cb98c1126..9e3259f19 100644 --- a/datapath/linux/Kbuild.in +++ b/datapath/linux/Kbuild.in @@ -18,10 +18,10 @@ ccflags-y += -include $(builddir)/kcompat.h # right place, even though it's conceptually incorrect. NOSTDINC_FLAGS += -I$(top_srcdir)/include -I$(srcdir)/compat -I$(srcdir)/compat/include -obj-m := $(patsubst %,%.o,$(build_modules)) +obj-m := $(subst _,-,$(patsubst %,%.o,$(build_modules))) define module_template $(1)-y = $$(notdir $$(patsubst %.c,%.o,$($(1)_sources))) endef -$(foreach module,$(build_modules),$(eval $(call module_template,$(module)))) +$(foreach module,$(build_multi_modules),$(eval $(call module_template,$(module)))) diff --git a/datapath/linux/compat/flow_dissector.c b/datapath/linux/compat/flow_dissector.c index ab60daa3b..a68f84f52 100644 --- a/datapath/linux/compat/flow_dissector.c +++ b/datapath/linux/compat/flow_dissector.c @@ -231,4 +231,5 @@ u32 __skb_get_hash(struct sk_buff *skb) #endif return hash; } +EXPORT_SYMBOL_GPL(__skb_get_hash); #endif diff --git a/datapath/linux/compat/geneve.c b/datapath/linux/compat/geneve.c index 35c01bb30..5fc6c6761 100644 --- a/datapath/linux/compat/geneve.c +++ b/datapath/linux/compat/geneve.c @@ -118,6 +118,7 @@ int geneve_xmit_skb(struct geneve_sock *gs, struct rtable *rt, tos, ttl, df, src_port, dst_port, xnet, !csum); } +EXPORT_SYMBOL_GPL(geneve_xmit_skb); /* Callback from net/ipv4/udp.c to receive packets */ static int geneve_udp_encap_recv(struct sock *sk, struct sk_buff *skb) @@ -226,6 +227,7 @@ struct geneve_sock *geneve_sock_add(struct net *net, __be16 port, { return geneve_socket_create(net, port, rcv, data, ipv6); } +EXPORT_SYMBOL_GPL(geneve_sock_add); static void rcu_free_gs(struct rcu_head *rcu) { @@ -239,3 +241,4 @@ void geneve_sock_release(struct geneve_sock *gs) udp_tunnel_sock_release(gs->sock); call_rcu(&gs->rcu, rcu_free_gs); } +EXPORT_SYMBOL_GPL(geneve_sock_release); diff --git a/datapath/linux/compat/gre.c b/datapath/linux/compat/gre.c index 22bbf2fb4..06956f049 100644 --- a/datapath/linux/compat/gre.c +++ b/datapath/linux/compat/gre.c @@ -250,6 +250,7 @@ int gre_cisco_register(struct gre_cisco_protocol *newp) return (cmpxchg((struct gre_cisco_protocol **)&gre_cisco_proto, NULL, newp) == NULL) ? 0 : -EBUSY; } +EXPORT_SYMBOL_GPL(gre_cisco_register); int gre_cisco_unregister(struct gre_cisco_protocol *proto) { @@ -265,6 +266,7 @@ int gre_cisco_unregister(struct gre_cisco_protocol *proto) ret = gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO); return ret; } +EXPORT_SYMBOL_GPL(gre_cisco_unregister); #endif /* !HAVE_GRE_CISCO_REGISTER */ @@ -297,6 +299,7 @@ struct sk_buff *gre_handle_offloads(struct sk_buff *skb, bool gre_csum) return ovs_iptunnel_handle_offloads(skb, gre_csum, type, fix_segment); } +EXPORT_SYMBOL_GPL(gre_handle_offloads); static bool is_gre_gso(struct sk_buff *skb) { @@ -334,6 +337,7 @@ void gre_build_header(struct sk_buff *skb, const struct tnl_ptk_info *tpi, ovs_skb_set_inner_protocol(skb, tpi->proto); } +EXPORT_SYMBOL_GPL(gre_build_header); #endif /* CONFIG_NET_IPGRE_DEMUX */ diff --git a/datapath/linux/compat/ip_tunnels_core.c b/datapath/linux/compat/ip_tunnels_core.c index 5e38603b9..f2c4ffd67 100644 --- a/datapath/linux/compat/ip_tunnels_core.c +++ b/datapath/linux/compat/ip_tunnels_core.c @@ -80,6 +80,7 @@ int rpl_iptunnel_xmit(struct sock *sk, struct rtable *rt, struct sk_buff *skb, pkt_len = 0; return pkt_len; } +EXPORT_SYMBOL_GPL(rpl_iptunnel_xmit); struct sk_buff *ovs_iptunnel_handle_offloads(struct sk_buff *skb, bool csum_help, int gso_type_mask, @@ -132,6 +133,7 @@ error: kfree_skb(skb); return ERR_PTR(err); } +EXPORT_SYMBOL_GPL(ovs_iptunnel_handle_offloads); int iptunnel_pull_header(struct sk_buff *skb, int hdr_len, __be16 inner_proto) { @@ -166,6 +168,7 @@ int iptunnel_pull_header(struct sk_buff *skb, int hdr_len, __be16 inner_proto) skb->pkt_type = PACKET_HOST; return 0; } +EXPORT_SYMBOL_GPL(iptunnel_pull_header); #endif @@ -176,3 +179,4 @@ bool skb_is_encapsulated(struct sk_buff *skb) */ return ovs_skb_get_inner_protocol(skb) || skb_encapsulation(skb); } +EXPORT_SYMBOL_GPL(skb_is_encapsulated); diff --git a/datapath/linux/compat/udp_tunnel.c b/datapath/linux/compat/udp_tunnel.c index a1c4951f2..f64011387 100644 --- a/datapath/linux/compat/udp_tunnel.c +++ b/datapath/linux/compat/udp_tunnel.c @@ -95,6 +95,7 @@ error: *sockp = NULL; return err; } +EXPORT_SYMBOL_GPL(udp_sock_create); void setup_udp_tunnel_sock(struct net *net, struct socket *sock, struct udp_tunnel_sock_cfg *cfg) @@ -114,6 +115,7 @@ void setup_udp_tunnel_sock(struct net *net, struct socket *sock, udp_tunnel_encap_enable(sock); } +EXPORT_SYMBOL_GPL(setup_udp_tunnel_sock); void ovs_udp_gso(struct sk_buff *skb) { @@ -123,6 +125,7 @@ void ovs_udp_gso(struct sk_buff *skb) uh = udp_hdr(skb); uh->len = htons(skb->len - udp_offset); } +EXPORT_SYMBOL_GPL(ovs_udp_gso); void ovs_udp_csum_gso(struct sk_buff *skb) { @@ -137,6 +140,7 @@ void ovs_udp_csum_gso(struct sk_buff *skb) udp_set_csum(true, skb, iph->saddr, iph->daddr, skb->len - udp_offset); } +EXPORT_SYMBOL_GPL(ovs_udp_csum_gso); int udp_tunnel_xmit_skb(struct rtable *rt, struct sk_buff *skb, __be32 src, __be32 dst, __u8 tos, __u8 ttl, @@ -158,6 +162,7 @@ int udp_tunnel_xmit_skb(struct rtable *rt, struct sk_buff *skb, return iptunnel_xmit(skb->sk, rt, skb, src, dst, IPPROTO_UDP, tos, ttl, df, xnet); } +EXPORT_SYMBOL_GPL(udp_tunnel_xmit_skb); void udp_tunnel_sock_release(struct socket *sock) { @@ -165,5 +170,6 @@ void udp_tunnel_sock_release(struct socket *sock) kernel_sock_shutdown(sock, SHUT_RDWR); sk_release_kernel(sock->sk); } +EXPORT_SYMBOL_GPL(udp_tunnel_sock_release); #endif /* Linux version < 3.20 */ diff --git a/datapath/linux/compat/vxlan.c b/datapath/linux/compat/vxlan.c index 960ddba63..8af3433ff 100644 --- a/datapath/linux/compat/vxlan.c +++ b/datapath/linux/compat/vxlan.c @@ -225,6 +225,7 @@ int vxlan_xmit_skb(struct vxlan_sock *vs, ttl, df, src_port, dst_port, xnet, !udp_sum); } +EXPORT_SYMBOL_GPL(vxlan_xmit_skb); static void rcu_free_vs(struct rcu_head *rcu) { @@ -313,6 +314,7 @@ struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port, { return vxlan_socket_create(net, port, rcv, data, flags); } +EXPORT_SYMBOL_GPL(vxlan_sock_add); void vxlan_sock_release(struct vxlan_sock *vs) { @@ -320,5 +322,6 @@ void vxlan_sock_release(struct vxlan_sock *vs) queue_work(system_wq, &vs->del_work); } +EXPORT_SYMBOL_GPL(vxlan_sock_release); #endif /* !USE_UPSTREAM_VXLAN */ diff --git a/datapath/vport-geneve.c b/datapath/vport-geneve.c index 624a6a0ec..2d7a6b38c 100644 --- a/datapath/vport-geneve.c +++ b/datapath/vport-geneve.c @@ -27,6 +27,8 @@ #include "datapath.h" #include "vport.h" +static struct vport_ops ovs_geneve_vport_ops; + /** * struct geneve_port - Keeps track of open UDP ports * @gs: The socket created for this port number. @@ -248,7 +250,7 @@ static int geneve_get_egress_tun_info(struct vport *vport, struct sk_buff *skb, IPPROTO_UDP, skb->mark, sport, dport); } -const struct vport_ops ovs_geneve_vport_ops = { +static struct vport_ops ovs_geneve_vport_ops = { .type = OVS_VPORT_TYPE_GENEVE, .create = geneve_tnl_create, .destroy = geneve_tnl_destroy, @@ -256,4 +258,22 @@ const struct vport_ops ovs_geneve_vport_ops = { .get_options = geneve_get_options, .send = geneve_tnl_send, .get_egress_tun_info = geneve_get_egress_tun_info, + .owner = THIS_MODULE, }; + +static int __init ovs_geneve_tnl_init(void) +{ + return ovs_vport_ops_register(&ovs_geneve_vport_ops); +} + +static void __exit ovs_geneve_tnl_exit(void) +{ + ovs_vport_ops_unregister(&ovs_geneve_vport_ops); +} + +module_init(ovs_geneve_tnl_init); +module_exit(ovs_geneve_tnl_exit); + +MODULE_DESCRIPTION("OVS: Geneve swiching port"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("vport-type-5"); diff --git a/datapath/vport-gre.c b/datapath/vport-gre.c index c0ed00972..7bbcf579f 100644 --- a/datapath/vport-gre.c +++ b/datapath/vport-gre.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -47,6 +48,9 @@ #include "datapath.h" #include "vport.h" +static struct vport_ops ovs_gre_vport_ops; +static struct vport_ops ovs_gre64_vport_ops; + /* Returns the least-significant 32 bits of a __be64. */ static __be32 be64_get_low32(__be64 x) { @@ -308,13 +312,14 @@ static int gre_get_egress_tun_info(struct vport *vport, struct sk_buff *skb, IPPROTO_GRE, skb->mark, 0, 0); } -const struct vport_ops ovs_gre_vport_ops = { +static struct vport_ops ovs_gre_vport_ops = { .type = OVS_VPORT_TYPE_GRE, .create = gre_create, .destroy = gre_tnl_destroy, .get_name = gre_get_name, .send = gre_send, .get_egress_tun_info = gre_get_egress_tun_info, + .owner = THIS_MODULE, }; /* GRE64 vport. */ @@ -387,12 +392,42 @@ static int gre64_send(struct vport *vport, struct sk_buff *skb) return __send(vport, skb, hlen, seq, (TUNNEL_KEY|TUNNEL_SEQ)); } -const struct vport_ops ovs_gre64_vport_ops = { +static struct vport_ops ovs_gre64_vport_ops = { .type = OVS_VPORT_TYPE_GRE64, .create = gre64_create, .destroy = gre64_tnl_destroy, .get_name = gre_get_name, .send = gre64_send, .get_egress_tun_info = gre_get_egress_tun_info, + .owner = THIS_MODULE, }; + +static int __init ovs_gre_tnl_init(void) +{ + int err; + + err = ovs_vport_ops_register(&ovs_gre_vport_ops); + if (err < 0) + return err; + + err = ovs_vport_ops_register(&ovs_gre64_vport_ops); + if (err < 0) + ovs_vport_ops_unregister(&ovs_gre_vport_ops); + + return err; +} + +static void __exit ovs_gre_tnl_exit(void) +{ + ovs_vport_ops_unregister(&ovs_gre64_vport_ops); + ovs_vport_ops_unregister(&ovs_gre_vport_ops); +} + +module_init(ovs_gre_tnl_init); +module_exit(ovs_gre_tnl_exit); + +MODULE_DESCRIPTION("OVS: GRE switching port"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("vport-type-3"); +MODULE_ALIAS("vport-type-104"); #endif diff --git a/datapath/vport-internal_dev.c b/datapath/vport-internal_dev.c index 040b37196..f38f9be07 100644 --- a/datapath/vport-internal_dev.c +++ b/datapath/vport-internal_dev.c @@ -38,6 +38,8 @@ struct internal_dev { struct vport *vport; }; +static struct vport_ops ovs_internal_vport_ops; + static struct internal_dev *internal_dev_priv(struct net_device *netdev) { return netdev_priv(netdev); @@ -285,7 +287,7 @@ static int internal_dev_recv(struct vport *vport, struct sk_buff *skb) return len; } -const struct vport_ops ovs_internal_vport_ops = { +static struct vport_ops ovs_internal_vport_ops = { .type = OVS_VPORT_TYPE_INTERNAL, .create = internal_dev_create, .destroy = internal_dev_destroy, @@ -308,10 +310,21 @@ struct vport *ovs_internal_dev_get_vport(struct net_device *netdev) int ovs_internal_dev_rtnl_link_register(void) { - return rtnl_link_register(&internal_dev_link_ops); + int err; + + err = rtnl_link_register(&internal_dev_link_ops); + if (err < 0) + return err; + + err = ovs_vport_ops_register(&ovs_internal_vport_ops); + if (err < 0) + rtnl_link_unregister(&internal_dev_link_ops); + + return err; } void ovs_internal_dev_rtnl_link_unregister(void) { + ovs_vport_ops_unregister(&ovs_internal_vport_ops); rtnl_link_unregister(&internal_dev_link_ops); } diff --git a/datapath/vport-lisp.c b/datapath/vport-lisp.c index 293002fe9..0024eb480 100644 --- a/datapath/vport-lisp.c +++ b/datapath/vport-lisp.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -110,6 +111,7 @@ struct lisp_port { }; static LIST_HEAD(lisp_ports); +static struct vport_ops ovs_lisp_vport_ops; static inline struct lisp_port *lisp_vport(const struct vport *vport) { @@ -493,7 +495,7 @@ static int lisp_get_egress_tun_info(struct vport *vport, struct sk_buff *skb, lisp_port->dst_port); } -const struct vport_ops ovs_lisp_vport_ops = { +static struct vport_ops ovs_lisp_vport_ops = { .type = OVS_VPORT_TYPE_LISP, .create = lisp_tnl_create, .destroy = lisp_tnl_destroy, @@ -501,4 +503,22 @@ const struct vport_ops ovs_lisp_vport_ops = { .get_options = lisp_get_options, .send = lisp_send, .get_egress_tun_info = lisp_get_egress_tun_info, + .owner = THIS_MODULE, }; + +static int __init ovs_lisp_tnl_init(void) +{ + return ovs_vport_ops_register(&ovs_lisp_vport_ops); +} + +static void __exit ovs_lisp_tnl_exit(void) +{ + ovs_vport_ops_unregister(&ovs_lisp_vport_ops); +} + +module_init(ovs_lisp_tnl_init); +module_exit(ovs_lisp_tnl_exit); + +MODULE_DESCRIPTION("OVS: LISP switching port"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("vport-type-105"); diff --git a/datapath/vport-netdev.c b/datapath/vport-netdev.c index 9c0908a03..05ad0b4ab 100644 --- a/datapath/vport-netdev.c +++ b/datapath/vport-netdev.c @@ -35,6 +35,7 @@ #include "vport-internal_dev.h" #include "vport-netdev.h" +static struct vport_ops ovs_netdev_vport_ops; static void netdev_port_receive(struct vport *vport, struct sk_buff *skb); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39) @@ -274,7 +275,7 @@ struct vport *ovs_netdev_get_vport(struct net_device *dev) #endif } -const struct vport_ops ovs_netdev_vport_ops = { +static struct vport_ops ovs_netdev_vport_ops = { .type = OVS_VPORT_TYPE_NETDEV, .create = netdev_create, .destroy = netdev_destroy, @@ -282,6 +283,16 @@ const struct vport_ops ovs_netdev_vport_ops = { .send = netdev_send, }; +int __init ovs_netdev_init(void) +{ + return ovs_vport_ops_register(&ovs_netdev_vport_ops); +} + +void ovs_netdev_exit(void) +{ + ovs_vport_ops_unregister(&ovs_netdev_vport_ops); +} + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) && \ !defined HAVE_RHEL_OVS_HOOK /* diff --git a/datapath/vport-netdev.h b/datapath/vport-netdev.h index 8df01c112..6f7038e79 100644 --- a/datapath/vport-netdev.h +++ b/datapath/vport-netdev.h @@ -41,4 +41,7 @@ netdev_vport_priv(const struct vport *vport) const char *ovs_netdev_get_name(const struct vport *); void ovs_netdev_detach_dev(struct vport *); +int __init ovs_netdev_init(void); +void ovs_netdev_exit(void); + #endif /* vport_netdev.h */ diff --git a/datapath/vport-vxlan.c b/datapath/vport-vxlan.c index c25cc5889..eff7ca23c 100644 --- a/datapath/vport-vxlan.c +++ b/datapath/vport-vxlan.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -54,6 +55,8 @@ struct vxlan_port { u32 exts; /* VXLAN_F_* in */ }; +static struct vport_ops ovs_vxlan_vport_ops; + static inline struct vxlan_port *vxlan_vport(const struct vport *vport) { return vport_priv(vport); @@ -293,7 +296,7 @@ static const char *vxlan_get_name(const struct vport *vport) return vxlan_port->name; } -const struct vport_ops ovs_vxlan_vport_ops = { +static struct vport_ops ovs_vxlan_vport_ops = { .type = OVS_VPORT_TYPE_VXLAN, .create = vxlan_tnl_create, .destroy = vxlan_tnl_destroy, @@ -301,4 +304,22 @@ const struct vport_ops ovs_vxlan_vport_ops = { .get_options = vxlan_get_options, .send = vxlan_tnl_send, .get_egress_tun_info = vxlan_get_egress_tun_info, + .owner = THIS_MODULE, }; + +static int __init ovs_vxlan_tnl_init(void) +{ + return ovs_vport_ops_register(&ovs_vxlan_vport_ops); +} + +static void __exit ovs_vxlan_tnl_exit(void) +{ + ovs_vport_ops_unregister(&ovs_vxlan_vport_ops); +} + +module_init(ovs_vxlan_tnl_init); +module_exit(ovs_vxlan_tnl_exit); + +MODULE_DESCRIPTION("OVS: VXLAN switching port"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("vport-type-4"); diff --git a/datapath/vport.c b/datapath/vport.c index 5a7067b2f..4486d06cd 100644 --- a/datapath/vport.c +++ b/datapath/vport.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -39,20 +40,7 @@ static void ovs_vport_record_error(struct vport *, enum vport_err_type err_type); -/* List of statically compiled vport implementations. Don't forget to also - * add yours to the list at the bottom of vport.h. - */ -static const struct vport_ops *vport_ops_list[] = { - &ovs_netdev_vport_ops, - &ovs_internal_vport_ops, - &ovs_geneve_vport_ops, -#if IS_ENABLED(CONFIG_NET_IPGRE_DEMUX) - &ovs_gre_vport_ops, - &ovs_gre64_vport_ops, -#endif - &ovs_vxlan_vport_ops, - &ovs_lisp_vport_ops, -}; +static LIST_HEAD(vport_ops_list); /* Protected by RCU read lock for reading, ovs_mutex for writing. */ static struct hlist_head *dev_table; @@ -89,6 +77,32 @@ static struct hlist_head *hash_bucket(const struct net *net, const char *name) return &dev_table[hash & (VPORT_HASH_BUCKETS - 1)]; } +int ovs_vport_ops_register(struct vport_ops *ops) +{ + int err = -EEXIST; + struct vport_ops *o; + + ovs_lock(); + list_for_each_entry(o, &vport_ops_list, list) + if (ops->type == o->type) + goto errout; + + list_add_tail(&ops->list, &vport_ops_list); + err = 0; +errout: + ovs_unlock(); + return err; +} +EXPORT_SYMBOL_GPL(ovs_vport_ops_register); + +void ovs_vport_ops_unregister(struct vport_ops *ops) +{ + ovs_lock(); + list_del(&ops->list); + ovs_unlock(); +} +EXPORT_SYMBOL_GPL(ovs_vport_ops_unregister); + /** * ovs_vport_locate - find a port that has already been created * @@ -154,6 +168,18 @@ struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *ops, return vport; } +EXPORT_SYMBOL_GPL(ovs_vport_alloc); + +static struct vport_ops *ovs_vport_lookup(const struct vport_parms *parms) +{ + struct vport_ops *ops; + + list_for_each_entry(ops, &vport_ops_list, list) + if (ops->type == parms->type) + return ops; + + return NULL; +} /** * ovs_vport_free - uninitialize and free vport @@ -171,6 +197,7 @@ void ovs_vport_free(struct vport *vport) free_percpu(vport->percpu_stats); kfree(vport); } +EXPORT_SYMBOL_GPL(ovs_vport_free); /** * ovs_vport_add - add vport device (for kernel callers) @@ -182,31 +209,40 @@ void ovs_vport_free(struct vport *vport) */ struct vport *ovs_vport_add(const struct vport_parms *parms) { + struct vport_ops *ops; struct vport *vport; - int err = 0; - int i; - for (i = 0; i < ARRAY_SIZE(vport_ops_list); i++) { - if (vport_ops_list[i]->type == parms->type) { - struct hlist_head *bucket; + ops = ovs_vport_lookup(parms); + if (ops) { + struct hlist_head *bucket; - vport = vport_ops_list[i]->create(parms); - if (IS_ERR(vport)) { - err = PTR_ERR(vport); - goto out; - } + if (!try_module_get(ops->owner)) + return ERR_PTR(-EAFNOSUPPORT); - bucket = hash_bucket(ovs_dp_get_net(vport->dp), - vport->ops->get_name(vport)); - hlist_add_head_rcu(&vport->hash_node, bucket); + vport = ops->create(parms); + if (IS_ERR(vport)) { + module_put(ops->owner); return vport; } + + bucket = hash_bucket(ovs_dp_get_net(vport->dp), + vport->ops->get_name(vport)); + hlist_add_head_rcu(&vport->hash_node, bucket); + return vport; } - err = -EAFNOSUPPORT; + /* Unlock to attempt module load and return -EAGAIN if load + * was successful as we need to restart the port addition + * workflow. + */ + ovs_unlock(); + request_module("vport-type-%d", parms->type); + ovs_lock(); -out: - return ERR_PTR(err); + if (!ovs_vport_lookup(parms)) + return ERR_PTR(-EAFNOSUPPORT); + else + return ERR_PTR(-EAGAIN); } /** @@ -238,6 +274,7 @@ void ovs_vport_del(struct vport *vport) ASSERT_OVSL(); hlist_del_rcu(&vport->hash_node); + module_put(vport->ops->owner); vport->ops->destroy(vport); } @@ -467,6 +504,7 @@ void ovs_vport_receive(struct vport *vport, struct sk_buff *skb, ovs_dp_process_packet(skb, &key); } +EXPORT_SYMBOL_GPL(ovs_vport_receive); /** * ovs_vport_send - send a packet on a device @@ -544,6 +582,7 @@ void ovs_vport_deferred_free(struct vport *vport) call_rcu(&vport->rcu, free_vport_rcu); } +EXPORT_SYMBOL_GPL(ovs_vport_deferred_free); int ovs_tunnel_get_egress_info(struct ovs_tunnel_info *egress_tun_info, struct net *net, @@ -592,6 +631,7 @@ int ovs_tunnel_get_egress_info(struct ovs_tunnel_info *egress_tun_info, return 0; } +EXPORT_SYMBOL_GPL(ovs_tunnel_get_egress_info); int ovs_vport_get_egress_tun_info(struct vport *vport, struct sk_buff *skb, struct ovs_tunnel_info *info) diff --git a/datapath/vport.h b/datapath/vport.h index e256fc0a4..c289d60ed 100644 --- a/datapath/vport.h +++ b/datapath/vport.h @@ -175,6 +175,9 @@ struct vport_ops { int (*send)(struct vport *, struct sk_buff *); int (*get_egress_tun_info)(struct vport *, struct sk_buff *, struct ovs_tunnel_info *); + + struct module *owner; + struct list_head list; }; enum vport_err_type { @@ -223,16 +226,6 @@ static inline struct vport *vport_from_priv(void *priv) void ovs_vport_receive(struct vport *, struct sk_buff *, const struct ovs_tunnel_info *); -/* List of statically compiled vport implementations. Don't forget to also - * add yours to the list at the top of vport.c. - */ -extern const struct vport_ops ovs_netdev_vport_ops; -extern const struct vport_ops ovs_internal_vport_ops; -extern const struct vport_ops ovs_geneve_vport_ops; -extern const struct vport_ops ovs_gre_vport_ops; -extern const struct vport_ops ovs_gre64_vport_ops; -extern const struct vport_ops ovs_vxlan_vport_ops; -extern const struct vport_ops ovs_lisp_vport_ops; static inline void ovs_skb_postpush_rcsum(struct sk_buff *skb, const void *start, unsigned int len) @@ -240,4 +233,7 @@ static inline void ovs_skb_postpush_rcsum(struct sk_buff *skb, if (skb->ip_summed == CHECKSUM_COMPLETE) skb->csum = csum_add(skb->csum, csum_partial(start, len, 0)); } + +int ovs_vport_ops_register(struct vport_ops *ops); +void ovs_vport_ops_unregister(struct vport_ops *ops); #endif /* vport.h */ -- cgit v1.2.1 From 1547aff66926f9f66f1e45c4d4723a1d9c940418 Mon Sep 17 00:00:00 2001 From: Kevin Lo Date: Sun, 5 Apr 2015 00:59:26 +0800 Subject: netdev-bsd: Fix sign extension bug in ifr_flags on FreeBSD. FreeBSD fills the int return value with ifr_flagshigh in the high 16 bits and ifr_flags in the low 16 bits rather than blindly promoting ifr_flags to an int, which will preserve the sign. This commit makes sure the flags returned isn't negative and apply mask 0xffff to flags. Signed-off-by: Kevin Lo Signed-off-by: Ben Pfaff --- lib/netdev-bsd.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/netdev-bsd.c b/lib/netdev-bsd.c index f97a5c35d..9ed2823b8 100644 --- a/lib/netdev-bsd.c +++ b/lib/netdev-bsd.c @@ -1785,7 +1785,7 @@ static int ifr_get_flags(const struct ifreq *ifr) { #ifdef HAVE_STRUCT_IFREQ_IFR_FLAGSHIGH - return (ifr->ifr_flagshigh << 16) | ifr->ifr_flags; + return (ifr->ifr_flagshigh << 16) | (ifr->ifr_flags & 0xffff); #else return ifr->ifr_flags; #endif @@ -1794,9 +1794,11 @@ ifr_get_flags(const struct ifreq *ifr) static void ifr_set_flags(struct ifreq *ifr, int flags) { - ifr->ifr_flags = flags; #ifdef HAVE_STRUCT_IFREQ_IFR_FLAGSHIGH + ifr->ifr_flags = flags & 0xffff; ifr->ifr_flagshigh = flags >> 16; +#else + ifr->ifr_flags = flags; #endif } -- cgit v1.2.1 From e1333833fa02571f1ae068e402b95bbc75c455b2 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Sun, 5 Apr 2015 09:58:06 -0700 Subject: AUTHORS: Add Kevin Lo. Signed-off-by: Ben Pfaff --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index 1d2201c46..d17ae7acb 100644 --- a/AUTHORS +++ b/AUTHORS @@ -92,6 +92,7 @@ Keith Amidon keith@nicira.com Ken Ajiro ajiro@mxw.nes.nec.co.jp Kenneth Duda kduda@arista.com Kentaro Ebisawa ebiken.g@gmail.com +Kevin Lo kevlo@FreeBSD.org Kevin Traynor kevin.traynor@intel.com Kmindg G kmindg@gmail.com Krishna Kondaka kkondaka@vmware.com -- cgit v1.2.1 From 4207d631d4841ddc38abdc0f2aea3b9fcb5ddfdc Mon Sep 17 00:00:00 2001 From: Justin Pettit Date: Sat, 4 Apr 2015 16:30:44 -0700 Subject: Makefile.am: Clarify error message about missing distribution files. The error message did not make it clear that the problem was due to files being in git but not the distribution. Signed-off-by: Justin Pettit Acked-by: Ben Pfaff --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index cada99707..8bc431bfc 100644 --- a/Makefile.am +++ b/Makefile.am @@ -202,7 +202,7 @@ dist-hook-git: distfiles LC_ALL=C sort -u > all-gitfiles; \ LC_ALL=C comm -1 -3 all-distfiles all-gitfiles > missing-distfiles; \ if test -s missing-distfiles; then \ - echo "The distribution is missing the following files:"; \ + echo "The following files are in git but not the distribution:"; \ cat missing-distfiles; \ exit 1; \ fi; \ -- cgit v1.2.1 From fdc14c7b33338c78b27d277c864f47c8a37adb36 Mon Sep 17 00:00:00 2001 From: Russell Bryant Date: Fri, 3 Apr 2015 16:04:14 -0400 Subject: ovs-sandbox: Tell gdb to start the daemon. The current gdb support launches gdb but doesn't start the daemon. If you start ovsdb-server with gdb, ovs-sandbox produces an error as it tries to run ovs-vsctl before ovsdb-server is running. Telling gdb to start the daemon immediately avoids this error. There are cases where it's useful to go straight to the gdb prompt, too. For example, someone may want to set a breakpoint. In that case, it's easy enough to just kill it, set a breakpoint, and execute 'run' again. In passing, fix indentation to use spaces instead of tabs. Signed-off-by: Russell Bryant Signed-off-by: Ben Pfaff --- tutorial/ovs-sandbox | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tutorial/ovs-sandbox b/tutorial/ovs-sandbox index 9520a41c4..251f021bc 100755 --- a/tutorial/ovs-sandbox +++ b/tutorial/ovs-sandbox @@ -35,8 +35,8 @@ rungdb() { # Use "DISPLAY" variable to determine out if X is supported if $under_gdb && [ "$DISPLAY" ]; then args=`echo $@ |sed s/--detach//g | sed s/--vconsole:off//g` - xterm_title=$1 - run_xterm $xterm_title gdb --args $args + xterm_title=$1 + run_xterm $xterm_title gdb -ex run --args $args else run $@ fi -- cgit v1.2.1 From 7e84c25dbbee56ef39434cacac0d8ce755da88bb Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Sun, 5 Apr 2015 12:12:12 -0700 Subject: xenserver: Package vport-*.ko with kernel module. Fixes a build error due to unpackaged files. Signed-off-by: Ben Pfaff Acked-by: Justin Pettit --- xenserver/openvswitch-xen.spec.in | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xenserver/openvswitch-xen.spec.in b/xenserver/openvswitch-xen.spec.in index 4d98d2e01..2902372e8 100644 --- a/xenserver/openvswitch-xen.spec.in +++ b/xenserver/openvswitch-xen.spec.in @@ -1,6 +1,6 @@ # Spec file for Open vSwitch. -# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc. +# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc. # # Copying and distribution of this file, with or without modification, # are permitted in any medium without royalty provided the copyright @@ -502,3 +502,4 @@ exit 0 %files %{module_package} /lib/modules/%{xen_version}/extra/openvswitch/openvswitch.ko +/lib/modules/%{xen_version}/extra/openvswitch/vport-*.ko -- cgit v1.2.1 From 31efbdb998b0267e245b8edc32b34c0dcc45e723 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Sun, 5 Apr 2015 12:12:13 -0700 Subject: rhel: Package vport-*.ko in Fedora kernel package. Fixes a presumed build break due to unpackaged files. (Only "presumed" at this point because it is masked in the VMware build system by the similar XenServer build failure.) Signed-off-by: Ben Pfaff Acked-by: Justin Pettit --- rhel/openvswitch-kmod-fedora.spec.in | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rhel/openvswitch-kmod-fedora.spec.in b/rhel/openvswitch-kmod-fedora.spec.in index ed3800226..8f79fd29b 100644 --- a/rhel/openvswitch-kmod-fedora.spec.in +++ b/rhel/openvswitch-kmod-fedora.spec.in @@ -1,6 +1,6 @@ # Spec file for Open vSwitch. -# Copyright (C) 2009, 2010 Nicira Networks, Inc. +# Copyright (C) 2009, 2010, 2015 Nicira Networks, Inc. # # Copying and distribution of this file, with or without modification, # are permitted in any medium without royalty provided the copyright @@ -56,6 +56,7 @@ depmod %{kernel} %files %defattr(-,root,root) /lib/modules/%{kernel}/kernel/extra/openvswitch/openvswitch.ko +/lib/modules/%{kernel}/kernel/extra/openvswitch/vport-*.ko %changelog * Wed Sep 21 2011 Kyle Mestery -- cgit v1.2.1 From 19c12401d654308b9ee0333c83a2df8e28161385 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Sun, 5 Apr 2015 12:12:14 -0700 Subject: ovs-dev.py: Remove vport-*.ko at same time as openvswitch.ko. My guess is that this is the intent. Signed-off-by: Ben Pfaff Acked-by: Justin Pettit Acked-by: Ethan Jackson --- utilities/ovs-dev.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/utilities/ovs-dev.py b/utilities/ovs-dev.py index 869d89e81..9467df521 100755 --- a/utilities/ovs-dev.py +++ b/utilities/ovs-dev.py @@ -1,5 +1,5 @@ #!/usr/bin/python -# Copyright (c) 2013, 2014 Nicira, Inc. +# Copyright (c) 2013, 2014, 2015 Nicira, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -269,7 +269,8 @@ def modinst(): pass # Module isn't loaded try: - _sh("rm /lib/modules/%s/extra/openvswitch.ko" % uname()) + _sh("rm -f /lib/modules/%s/extra/openvswitch.ko" % uname()) + _sh("rm -f /lib/modules/%s/extra/vport-*.ko" % uname()) except subprocess.CalledProcessError, e: pass # Module isn't installed -- cgit v1.2.1 From ce5112573fa58d34ca87dc488ec0d996f8c7f0d8 Mon Sep 17 00:00:00 2001 From: Alin Serdean Date: Mon, 6 Apr 2015 17:28:42 +0000 Subject: datapath-windows: Allow NdisSwitchPortTypeSynthetic to be updated Allow the port to be updated if it the type is only: NdisSwitchPortTypeSynthetic Acked-by: Nithin Raju Acked-by: Eitan Eliahu Acked-by: Sorin Vinturis Signed-off-by: Alin Gabriel Serdean Signed-off-by: Ben Pfaff --- datapath-windows/ovsext/Vport.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/datapath-windows/ovsext/Vport.c b/datapath-windows/ovsext/Vport.c index 12751beaf..38bbcfa2d 100644 --- a/datapath-windows/ovsext/Vport.c +++ b/datapath-windows/ovsext/Vport.c @@ -167,8 +167,8 @@ HvUpdatePort(POVS_SWITCH_CONTEXT switchContext, * Update properties only for NETDEV ports for supprting PS script * We don't allow changing the names of the internal or external ports */ - if (vport == NULL || ( vport->portType != NdisSwitchPortTypeSynthetic) || - ( vport->portType != NdisSwitchPortTypeEmulated)) { + if (vport == NULL || (( vport->portType != NdisSwitchPortTypeSynthetic) && + ( vport->portType != NdisSwitchPortTypeEmulated))) { goto update_port_done; } -- cgit v1.2.1 From 6c6045a72a93f72317567cc6075ac306ef0a3c44 Mon Sep 17 00:00:00 2001 From: Alin Serdean Date: Mon, 6 Apr 2015 17:22:06 +0000 Subject: datapath-windows Release lock on HVUpdateNIC Release switchContext->dispatchLock in case the vport has not been found. Acked-by: Eitan Eliahu Acked-by: Sorin Vinturis Signed-off-by: Alin Gabriel Serdean Signed-off-by: Ben Pfaff --- datapath-windows/ovsext/Vport.c | 1 + 1 file changed, 1 insertion(+) diff --git a/datapath-windows/ovsext/Vport.c b/datapath-windows/ovsext/Vport.c index 38bbcfa2d..f46a0ac04 100644 --- a/datapath-windows/ovsext/Vport.c +++ b/datapath-windows/ovsext/Vport.c @@ -404,6 +404,7 @@ HvUpdateNic(POVS_SWITCH_CONTEXT switchContext, nicParam->PortId, nicParam->NicIndex); if (vport == NULL) { + NdisReleaseRWLock(switchContext->dispatchLock, &lockState); OVS_LOG_WARN("Vport search failed."); goto update_nic_done; } -- cgit v1.2.1 From 660527a420c29bdbc0cddd51438980ee712ba591 Mon Sep 17 00:00:00 2001 From: Dennis Flynn Date: Mon, 6 Apr 2015 10:59:19 -0400 Subject: auto-attach: Fix segfault when enabling auto attach. This commit fixes a segmentation fault observed when enabling lldp prior to establishing auto attach mappings. Signed-off-by: Dennis Flynn Signed-off-by: Ben Pfaff --- lib/ovs-lldp.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/ovs-lldp.c b/lib/ovs-lldp.c index db97648e6..f71b40ddb 100644 --- a/lib/ovs-lldp.c +++ b/lib/ovs-lldp.c @@ -483,12 +483,14 @@ aa_configure(const struct aa_settings *s) LIST_FOR_EACH (chassis, list, &lldp->lldpd->g_chassis) { /* System Description */ free(chassis->c_descr); - chassis->c_descr = s->system_description[0] ? + chassis->c_descr = s && s->system_description[0] ? xstrdup(s->system_description) : xstrdup(PACKAGE_STRING); /* System Name */ - free(chassis->c_name); - chassis->c_name = xstrdup(s->system_name); + if (s) { + free(chassis->c_name); + chassis->c_name = xstrdup(s->system_name); + } } } -- cgit v1.2.1 From 5f03c98321092da7ff0246117098a7df197b2ce2 Mon Sep 17 00:00:00 2001 From: Jarno Rajahalme Date: Mon, 6 Apr 2015 14:02:28 -0700 Subject: lib/list: Add LIST_FOR_EACH_POP. Makes popping each member of the list a bit easier. Signed-off-by: Jarno Rajahalme Acked-by: Russell Bryant Acked-by: Ben Pfaff --- lib/dp-packet.c | 5 ++--- lib/list.h | 3 +++ lib/lldp/lldpd-structs.c | 5 ++--- lib/lldp/lldpd.c | 5 ++--- lib/mcast-snooping.c | 5 ++--- lib/ofp-util.c | 5 ++--- lib/ofpbuf.c | 5 ++--- lib/ovs-lldp.c | 8 ++------ lib/ovs-numa.c | 5 ++--- lib/ovs-rcu.c | 5 ++--- lib/vconn.c | 6 ++---- ofproto/bundles.c | 5 ++--- ofproto/connmgr.c | 16 ++++++---------- ofproto/ofproto-dpif-rid.c | 5 ++--- ofproto/ofproto-dpif-xlate.c | 5 ++--- ofproto/ofproto-dpif.c | 15 ++++++--------- ofproto/ofproto.c | 5 ++--- tests/library.at | 2 +- tests/test-list.c | 26 ++++++++++++++++++++++++++ 19 files changed, 70 insertions(+), 66 deletions(-) diff --git a/lib/dp-packet.c b/lib/dp-packet.c index 88b570886..8a4cf43ea 100644 --- a/lib/dp-packet.c +++ b/lib/dp-packet.c @@ -465,10 +465,9 @@ dp_packet_to_string(const struct dp_packet *b, size_t maxbytes) void dp_packet_list_delete(struct ovs_list *list) { - struct dp_packet *b, *next; + struct dp_packet *b; - LIST_FOR_EACH_SAFE (b, next, list_node, list) { - list_remove(&b->list_node); + LIST_FOR_EACH_POP (b, list_node, list) { dp_packet_delete(b); } } diff --git a/lib/list.h b/lib/list.h index b40bbef72..7ba1e3549 100644 --- a/lib/list.h +++ b/lib/list.h @@ -73,6 +73,9 @@ static inline bool list_is_short(const struct ovs_list *); ? INIT_CONTAINER(NEXT, (ITER)->MEMBER.next, MEMBER), 1 \ : 0); \ (ITER) = (NEXT)) +#define LIST_FOR_EACH_POP(ITER, MEMBER, LIST) \ + while (!list_is_empty(LIST) \ + && (INIT_CONTAINER(ITER, list_pop_front(LIST), MEMBER), 1)) /* Inline implementations. */ diff --git a/lib/lldp/lldpd-structs.c b/lib/lldp/lldpd-structs.c index e2f8f2293..b78c2e19a 100644 --- a/lib/lldp/lldpd-structs.c +++ b/lib/lldp/lldpd-structs.c @@ -28,13 +28,12 @@ VLOG_DEFINE_THIS_MODULE(lldpd_structs); void lldpd_chassis_mgmt_cleanup(struct lldpd_chassis *chassis) { - struct lldpd_mgmt *mgmt, *mgmt_next; + struct lldpd_mgmt *mgmt; VLOG_DBG("cleanup management addresses for chassis %s", chassis->c_name ? chassis->c_name : "(unknown)"); - LIST_FOR_EACH_SAFE (mgmt, mgmt_next, m_entries, &chassis->c_mgmt) { - list_remove(&mgmt->m_entries); + LIST_FOR_EACH_POP (mgmt, m_entries, &chassis->c_mgmt) { free(mgmt); } diff --git a/lib/lldp/lldpd.c b/lib/lldp/lldpd.c index 7f6e348b0..71d3938d1 100644 --- a/lib/lldp/lldpd.c +++ b/lib/lldp/lldpd.c @@ -164,7 +164,7 @@ static void lldpd_move_chassis(struct lldpd_chassis *ochassis, struct lldpd_chassis *chassis) { - struct lldpd_mgmt *mgmt, *mgmt_next; + struct lldpd_mgmt *mgmt; int refcount = ochassis->c_refcount; int index = ochassis->c_index; struct ovs_list listcopy; @@ -182,8 +182,7 @@ lldpd_move_chassis(struct lldpd_chassis *ochassis, list_init(&ochassis->c_mgmt); /* Copy of management addresses */ - LIST_FOR_EACH_SAFE (mgmt, mgmt_next, m_entries, &chassis->c_mgmt) { - list_remove(&mgmt->m_entries); + LIST_FOR_EACH_POP (mgmt, m_entries, &chassis->c_mgmt) { list_insert(&ochassis->c_mgmt, &mgmt->m_entries); } diff --git a/lib/mcast-snooping.c b/lib/mcast-snooping.c index 6fe3890c7..c3ffd6b77 100644 --- a/lib/mcast-snooping.c +++ b/lib/mcast-snooping.c @@ -307,10 +307,9 @@ static void mcast_snooping_flush_group(struct mcast_snooping *ms, struct mcast_group *grp) OVS_REQ_WRLOCK(ms->rwlock) { - struct mcast_group_bundle *b, *next_b; + struct mcast_group_bundle *b; - LIST_FOR_EACH_SAFE (b, next_b, bundle_node, &grp->bundle_lru) { - list_remove(&b->bundle_node); + LIST_FOR_EACH_POP (b, bundle_node, &grp->bundle_lru) { free(b); } mcast_snooping_flush_group__(ms, grp); diff --git a/lib/ofp-util.c b/lib/ofp-util.c index a0da289d0..277fdfeb2 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -6886,10 +6886,9 @@ ofputil_decode_port_stats_request(const struct ofp_header *request, void ofputil_bucket_list_destroy(struct ovs_list *buckets) { - struct ofputil_bucket *bucket, *next_bucket; + struct ofputil_bucket *bucket; - LIST_FOR_EACH_SAFE (bucket, next_bucket, list_node, buckets) { - list_remove(&bucket->list_node); + LIST_FOR_EACH_POP (bucket, list_node, buckets) { free(bucket->ofpacts); free(bucket); } diff --git a/lib/ofpbuf.c b/lib/ofpbuf.c index 7510edb9b..c27c55204 100644 --- a/lib/ofpbuf.c +++ b/lib/ofpbuf.c @@ -477,10 +477,9 @@ ofpbuf_to_string(const struct ofpbuf *b, size_t maxbytes) void ofpbuf_list_delete(struct ovs_list *list) { - struct ofpbuf *b, *next; + struct ofpbuf *b; - LIST_FOR_EACH_SAFE (b, next, list_node, list) { - list_remove(&b->list_node); + LIST_FOR_EACH_POP (b, list_node, list) { ofpbuf_delete(b); } } diff --git a/lib/ovs-lldp.c b/lib/ovs-lldp.c index f71b40ddb..3edaf429a 100644 --- a/lib/ovs-lldp.c +++ b/lib/ovs-lldp.c @@ -421,12 +421,9 @@ aa_get_vlan_queued(struct ovs_list *list) ovs_mutex_lock(&mutex); HMAP_FOR_EACH (lldp, hmap_node, all_lldps) { - struct bridge_aa_vlan *node, *node_next; + struct bridge_aa_vlan *node; - LIST_FOR_EACH_SAFE (node, - node_next, - list_node, - &lldp->active_mapping_queue) { + LIST_FOR_EACH_POP (node, list_node, &lldp->active_mapping_queue) { struct bridge_aa_vlan *copy; copy = xmalloc(sizeof *copy); @@ -437,7 +434,6 @@ aa_get_vlan_queued(struct ovs_list *list) list_push_back(list, ©->list_node); /* Cleanup */ - list_remove(&node->list_node); free(node->port_name); free(node); } diff --git a/lib/ovs-numa.c b/lib/ovs-numa.c index 3aa103694..5bed2b5e2 100644 --- a/lib/ovs-numa.c +++ b/lib/ovs-numa.c @@ -380,10 +380,9 @@ ovs_numa_dump_cores_on_numa(int numa_id) void ovs_numa_dump_destroy(struct ovs_numa_dump *dump) { - struct ovs_numa_info *iter, *next; + struct ovs_numa_info *iter; - LIST_FOR_EACH_SAFE (iter, next, list_node, &dump->dump) { - list_remove(&iter->list_node); + LIST_FOR_EACH_POP (iter, list_node, &dump->dump) { free(iter); } diff --git a/lib/ovs-rcu.c b/lib/ovs-rcu.c index 5276981c8..76659bbe0 100644 --- a/lib/ovs-rcu.c +++ b/lib/ovs-rcu.c @@ -239,7 +239,7 @@ ovsrcu_postpone__(void (*function)(void *aux), void *aux) static bool ovsrcu_call_postponed(void) { - struct ovsrcu_cbset *cbset, *next_cbset; + struct ovsrcu_cbset *cbset; struct ovs_list cbsets; guarded_list_pop_all(&flushed_cbsets, &cbsets); @@ -249,13 +249,12 @@ ovsrcu_call_postponed(void) ovsrcu_synchronize(); - LIST_FOR_EACH_SAFE (cbset, next_cbset, list_node, &cbsets) { + LIST_FOR_EACH_POP (cbset, list_node, &cbsets) { struct ovsrcu_cb *cb; for (cb = cbset->cbs; cb < &cbset->cbs[cbset->n_cbs]; cb++) { cb->function(cb->aux); } - list_remove(&cbset->list_node); free(cbset); } diff --git a/lib/vconn.c b/lib/vconn.c index a59829d52..c033b48d8 100644 --- a/lib/vconn.c +++ b/lib/vconn.c @@ -881,13 +881,11 @@ int vconn_transact_multiple_noreply(struct vconn *vconn, struct ovs_list *requests, struct ofpbuf **replyp) { - struct ofpbuf *request, *next; + struct ofpbuf *request; - LIST_FOR_EACH_SAFE (request, next, list_node, requests) { + LIST_FOR_EACH_POP (request, list_node, requests) { int error; - list_remove(&request->list_node); - error = vconn_transact_noreply(vconn, request, replyp); if (error || *replyp) { ofpbuf_list_delete(requests); diff --git a/ofproto/bundles.c b/ofproto/bundles.c index 4d9deacf9..c40909150 100644 --- a/ofproto/bundles.c +++ b/ofproto/bundles.c @@ -100,11 +100,10 @@ ofp_bundle_create(uint32_t id, uint16_t flags) static void ofp_bundle_remove(struct ofconn *ofconn, struct ofp_bundle *item) { - struct bundle_message *msg, *next; + struct bundle_message *msg; struct hmap *bundles; - LIST_FOR_EACH_SAFE (msg, next, node, &item->msg_list) { - list_remove(&msg->node); + LIST_FOR_EACH_POP (msg, node, &item->msg_list) { free(msg->msg); free(msg); } diff --git a/ofproto/connmgr.c b/ofproto/connmgr.c index f34652bfa..707385f00 100644 --- a/ofproto/connmgr.c +++ b/ofproto/connmgr.c @@ -1093,10 +1093,9 @@ ofconn_send_reply(const struct ofconn *ofconn, struct ofpbuf *msg) void ofconn_send_replies(const struct ofconn *ofconn, struct ovs_list *replies) { - struct ofpbuf *reply, *next; + struct ofpbuf *reply; - LIST_FOR_EACH_SAFE (reply, next, list_node, replies) { - list_remove(&reply->list_node); + LIST_FOR_EACH_POP (reply, list_node, replies) { ofconn_send_reply(ofconn, reply); } } @@ -1724,11 +1723,9 @@ connmgr_send_packet_in(struct connmgr *mgr, static void do_send_packet_ins(struct ofconn *ofconn, struct ovs_list *txq) { - struct ofpbuf *pin, *next_pin; - - LIST_FOR_EACH_SAFE (pin, next_pin, list_node, txq) { - list_remove(&pin->list_node); + struct ofpbuf *pin; + LIST_FOR_EACH_POP (pin, list_node, txq) { if (rconn_send_with_limit(ofconn->rconn, pin, ofconn->packet_in_counter, 100) == EAGAIN) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5); @@ -2255,12 +2252,11 @@ ofmonitor_flush(struct connmgr *mgr) struct ofconn *ofconn; LIST_FOR_EACH (ofconn, node, &mgr->all_conns) { - struct ofpbuf *msg, *next; + struct ofpbuf *msg; - LIST_FOR_EACH_SAFE (msg, next, list_node, &ofconn->updates) { + LIST_FOR_EACH_POP (msg, list_node, &ofconn->updates) { unsigned int n_bytes; - list_remove(&msg->list_node); ofconn_send(ofconn, msg, ofconn->monitor_counter); n_bytes = rconn_packet_counter_n_bytes(ofconn->monitor_counter); if (!ofconn->monitor_paused && n_bytes > 128 * 1024) { diff --git a/ofproto/ofproto-dpif-rid.c b/ofproto/ofproto-dpif-rid.c index 17bcede62..f1b3bdcf8 100644 --- a/ofproto/ofproto-dpif-rid.c +++ b/ofproto/ofproto-dpif-rid.c @@ -67,7 +67,7 @@ recirc_run(void) /* Do maintenance at most 4 times / sec. */ ovs_mutex_lock(&mutex); if (now - last > 250) { - struct recirc_id_node *node, *next; + struct recirc_id_node *node; last = now; @@ -86,8 +86,7 @@ recirc_run(void) /* Delete the expired. These have been lingering for at least 250 ms, * which should be enough for any ongoing recirculations to be * finished. */ - LIST_FOR_EACH_SAFE (node, next, exp_node, &expired) { - list_remove(&node->exp_node); + LIST_FOR_EACH_POP (node, exp_node, &expired) { cmap_remove(&id_map, &node->id_node, node->id); ovsrcu_postpone(free, node); } diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index 4f82238be..55ae6831a 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -949,14 +949,13 @@ xlate_bundle_set(struct ofproto_dpif *ofproto, struct ofbundle *ofbundle, static void xlate_xbundle_remove(struct xlate_cfg *xcfg, struct xbundle *xbundle) { - struct xport *xport, *next; + struct xport *xport; if (!xbundle) { return; } - LIST_FOR_EACH_SAFE (xport, next, bundle_node, &xbundle->xports) { - list_remove(&xport->bundle_node); + LIST_FOR_EACH_POP (xport, bundle_node, &xbundle->xports) { xport->xbundle = NULL; } diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 837ae0bd3..01d99c54a 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -886,7 +886,7 @@ open_dpif_backer(const char *type, struct dpif_backer **backerp) struct dpif_port port; struct shash_node *node; struct ovs_list garbage_list; - struct odp_garbage *garbage, *next; + struct odp_garbage *garbage; struct sset names; char *backer_name; @@ -964,9 +964,8 @@ open_dpif_backer(const char *type, struct dpif_backer **backerp) } dpif_port_dump_done(&port_dump); - LIST_FOR_EACH_SAFE (garbage, next, list_node, &garbage_list) { + LIST_FOR_EACH_POP (garbage, list_node, &garbage_list) { dpif_port_del(backer->dpif, garbage->odp_port); - list_remove(&garbage->list_node); free(garbage); } @@ -1377,7 +1376,7 @@ static void destruct(struct ofproto *ofproto_) { struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_); - struct ofproto_packet_in *pin, *next_pin; + struct ofproto_packet_in *pin; struct rule_dpif *rule; struct oftable *table; struct ovs_list pins; @@ -1400,8 +1399,7 @@ destruct(struct ofproto *ofproto_) } guarded_list_pop_all(&ofproto->pins, &pins); - LIST_FOR_EACH_SAFE (pin, next_pin, list_node, &pins) { - list_remove(&pin->list_node); + LIST_FOR_EACH_POP (pin, list_node, &pins) { free(CONST_CAST(void *, pin->up.packet)); free(pin); } @@ -1456,13 +1454,12 @@ run(struct ofproto *ofproto_) /* Do not perform any periodic activity required by 'ofproto' while * waiting for flow restore to complete. */ if (!ofproto_get_flow_restore_wait()) { - struct ofproto_packet_in *pin, *next_pin; + struct ofproto_packet_in *pin; struct ovs_list pins; guarded_list_pop_all(&ofproto->pins, &pins); - LIST_FOR_EACH_SAFE (pin, next_pin, list_node, &pins) { + LIST_FOR_EACH_POP (pin, list_node, &pins) { connmgr_send_packet_in(ofproto->up.connmgr, pin); - list_remove(&pin->list_node); free(CONST_CAST(void *, pin->up.packet)); free(pin); } diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index a36a1f8cc..927521bb2 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -2961,9 +2961,9 @@ static void learned_cookies_flush(struct ofproto *ofproto, struct ovs_list *dead_cookies) OVS_REQUIRES(ofproto_mutex) { - struct learned_cookie *c, *next; + struct learned_cookie *c; - LIST_FOR_EACH_SAFE (c, next, u.list_node, dead_cookies) { + LIST_FOR_EACH_POP (c, u.list_node, dead_cookies) { struct rule_criteria criteria; struct rule_collection rules; struct match match; @@ -2977,7 +2977,6 @@ learned_cookies_flush(struct ofproto *ofproto, struct ovs_list *dead_cookies) rule_criteria_destroy(&criteria); rule_collection_destroy(&rules); - list_remove(&c->u.list_node); free(c); } } diff --git a/tests/library.at b/tests/library.at index 250768815..dfc5ad958 100644 --- a/tests/library.at +++ b/tests/library.at @@ -38,7 +38,7 @@ AT_CHECK([ovstest test-atomic]) AT_CLEANUP AT_SETUP([test linked lists]) -AT_CHECK([ovstest test-list], [0], [.. +AT_CHECK([ovstest test-list], [0], [... ]) AT_CLEANUP diff --git a/tests/test-list.c b/tests/test-list.c index 5fd7149c7..9b6b0bde9 100644 --- a/tests/test-list.c +++ b/tests/test-list.c @@ -159,6 +159,31 @@ test_list_for_each_safe(void) } } +/* Tests that LIST_FOR_EACH_POP removes the elements of a list. */ +static void +test_list_for_each_pop(void) +{ + enum { MAX_ELEMS = 10 }; + size_t n; + + for (n = 0; n <= MAX_ELEMS; n++) { + struct element elements[MAX_ELEMS]; + int values[MAX_ELEMS]; + struct ovs_list list; + struct element *e; + size_t n_remaining; + + make_list(&list, elements, values, n); + + n_remaining = n; + LIST_FOR_EACH_POP (e, node, &list) { + n_remaining--; + memmove(values, values + 1, sizeof *values * n_remaining); + check_list(&list, values, n_remaining); + } + } +} + static void run_test(void (*function)(void)) { @@ -171,6 +196,7 @@ test_list_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) { run_test(test_list_construction); run_test(test_list_for_each_safe); + run_test(test_list_for_each_pop); printf("\n"); } -- cgit v1.2.1 From 500ce35e8d2ef05295dd9e3b6147cd55dd79df55 Mon Sep 17 00:00:00 2001 From: Alex Wang Date: Tue, 31 Mar 2015 16:53:47 -0700 Subject: bridge: Do not wait for status update when there is no bridge. Signed-off-by: Alex Wang Acked-by: Ben Pfaff --- vswitchd/bridge.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index afd7c3e66..5ea4d66e1 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -2826,12 +2826,6 @@ run_status_update(void) static void status_update_wait(void) { - /* This prevents the process from constantly waking up on - * connectivity seq, when there is no connection to ovsdb. */ - if (!ovsdb_idl_has_lock(idl)) { - return; - } - /* If the 'status_txn' is non-null (transaction incomplete), waits for the * transaction to complete. If the status update to database needs to be * run again (transaction fails), registers a timeout in @@ -3019,9 +3013,9 @@ bridge_wait(void) } poll_timer_wait_until(stats_timer); + status_update_wait(); } - status_update_wait(); system_stats_wait(); } -- cgit v1.2.1 From 131d04dcc4190d4202d605bd982047084e987fba Mon Sep 17 00:00:00 2001 From: Alex Wang Date: Tue, 31 Mar 2015 17:07:03 -0700 Subject: bridge: Wait for previous stats update transation when it is incomplete. When ovsdb happens to get blocked for few seconds, the 'stats_timer' will not be updated due to incompletion of previous transaction. When the current time passes the 'stats_timer', the call to poll_timer_wait_until(stats_timer) will keep waking up ovs-vswitchd, causing 100% cpu utilization. This commit fixes this issue by making ovs-vswitchd wait on the previous idl transaction when it is incomplete rather than the 'stats_timer'. Signed-off-by: Alex Wang Acked-by: Ben Pfaff --- vswitchd/bridge.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index 5ea4d66e1..ea7d78838 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -203,6 +203,9 @@ static bool status_txn_try_again; * timeout in 'STATUS_CHECK_AGAIN_MSEC' to check again. */ #define STATUS_CHECK_AGAIN_MSEC 100 +/* Statistics update to database. */ +static struct ovsdb_idl_txn *stats_txn; + /* Each time this timer expires, the bridge fetches interface and mirror * statistics and pushes them into the database. */ static int stats_timer_interval; @@ -2693,7 +2696,6 @@ refresh_controller_status(void) static void run_stats_update(void) { - static struct ovsdb_idl_txn *stats_txn; const struct ovsrec_open_vswitch *cfg = ovsrec_open_vswitch_first(idl); int stats_interval; @@ -2748,6 +2750,18 @@ run_stats_update(void) } } +static void +stats_update_wait(void) +{ + /* If the 'stats_txn' is non-null (transaction incomplete), waits for the + * transaction to complete. Otherwise, waits for the 'stats_timer'. */ + if (stats_txn) { + ovsdb_idl_txn_wait(stats_txn); + } else { + poll_timer_wait_until(stats_timer); + } +} + /* Update bridge/port/interface status if necessary. */ static void run_status_update(void) @@ -3011,8 +3025,7 @@ bridge_wait(void) HMAP_FOR_EACH (br, node, &all_bridges) { ofproto_wait(br->ofproto); } - - poll_timer_wait_until(stats_timer); + stats_update_wait(); status_update_wait(); } -- cgit v1.2.1 From 48627758026da115f30ca71a5f651dbc434a8664 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Mon, 6 Apr 2015 14:39:06 -0700 Subject: hmap: Add comment warning about pitfall in HMAP_FOR_EACH_* usage. CC: Russell Bryant Signed-off-by: Ben Pfaff Acked-by: Justin Pettit --- lib/hmap.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/hmap.h b/lib/hmap.h index dc1e85ca5..345bf7fd4 100644 --- a/lib/hmap.h +++ b/lib/hmap.h @@ -123,6 +123,16 @@ struct hmap_node *hmap_random_node(const struct hmap *); * iteration). * * HASH is only evaluated once. + * + * + * Warning + * ------- + * + * When the loop terminates, &NODE->MEMBER will equal NULL. Unless MEMBER is + * the first member in its struct, this means that NODE itself will not be + * NULL. + * + * (This is true for all of the HMAP_FOR_EACH_*() macros.) */ #define HMAP_FOR_EACH_WITH_HASH(NODE, MEMBER, HASH, HMAP) \ for (INIT_CONTAINER(NODE, hmap_first_with_hash(HMAP, HASH), MEMBER); \ -- cgit v1.2.1 From dd2a1e9c59c75dc9bac4f5bc4aee70a1af568e07 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Mon, 6 Apr 2015 13:56:04 -0700 Subject: rhel: Make Fedora %files and %install section wildcards match. Since %install puts every .ko file into /lib/modules, %files should make sure that all of them are packaged. Suggested-by: Thomas Graf Signed-off-by: Ben Pfaff Acked-by: Flavio Leitner --- rhel/openvswitch-kmod-fedora.spec.in | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/rhel/openvswitch-kmod-fedora.spec.in b/rhel/openvswitch-kmod-fedora.spec.in index 8f79fd29b..ecea16c8b 100644 --- a/rhel/openvswitch-kmod-fedora.spec.in +++ b/rhel/openvswitch-kmod-fedora.spec.in @@ -55,8 +55,7 @@ depmod %{kernel} %files %defattr(-,root,root) -/lib/modules/%{kernel}/kernel/extra/openvswitch/openvswitch.ko -/lib/modules/%{kernel}/kernel/extra/openvswitch/vport-*.ko +/lib/modules/%{kernel}/kernel/extra/openvswitch/*.ko %changelog * Wed Sep 21 2011 Kyle Mestery -- cgit v1.2.1 From f293a803d9ece7157ec5d098deb1bf29e5de5915 Mon Sep 17 00:00:00 2001 From: Kevin Lo Date: Tue, 7 Apr 2015 16:18:47 +0800 Subject: specify -w to set variables for sysctl(8) on NetBSD We have to specify -w to set tunable sysctls on NetBSD. Signed-off-by: Kevin Lo Signed-off-by: Ben Pfaff Acked-by: YAMAMOTO Takashi --- INSTALL.userspace.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/INSTALL.userspace.md b/INSTALL.userspace.md index 300d6c131..04c02cd8a 100644 --- a/INSTALL.userspace.md +++ b/INSTALL.userspace.md @@ -76,7 +76,7 @@ Other settings On NetBSD, depending on your network topology and applications, the following configuration might help. See sysctl(7). - sysctl net.inet.ip.checkinterface=1 + sysctl -w net.inet.ip.checkinterface=1 Bug Reporting ------------- -- cgit v1.2.1 From 6c4e7adb0807155b603eef30a7929c42667bfa38 Mon Sep 17 00:00:00 2001 From: Sorin Vinturis Date: Tue, 7 Apr 2015 16:35:54 +0000 Subject: datapath-windows: Solved BSOD when uninstalling the driver (race condition) The BSOD occurred because the FilterAttach routine released the switch context, while there were IRPs in processing. The solution was to add a reference count to prevent premature deallocation of the global switch context structure, gOvsSwitchContext. Signed-off-by: Sorin Vinturis Reported-by: Alin Gabriel Serdean Reported-at: https://github.com/openvswitch/ovs-issues/issues/58 Acked-by: Eitan Eliahu Signed-off-by: Gurucharan Shetty --- datapath-windows/ovsext/Datapath.c | 12 ++++++-- datapath-windows/ovsext/Switch.c | 56 ++++++++++++++++++++++++++++++++++++++ datapath-windows/ovsext/Switch.h | 6 +++- 3 files changed, 71 insertions(+), 3 deletions(-) diff --git a/datapath-windows/ovsext/Datapath.c b/datapath-windows/ovsext/Datapath.c index e566ea9d0..fea7d3a7a 100644 --- a/datapath-windows/ovsext/Datapath.c +++ b/datapath-windows/ovsext/Datapath.c @@ -717,8 +717,13 @@ OvsDeviceControl(PDEVICE_OBJECT deviceObject, /* Check if the extension is enabled. */ if (NULL == gOvsSwitchContext) { - status = STATUS_DEVICE_NOT_READY; - goto done; + status = STATUS_NOT_FOUND; + goto exit; + } + + if (!OvsAcquireSwitchContext()) { + status = STATUS_NOT_FOUND; + goto exit; } /* Concurrent netlink operations are not supported. */ @@ -908,6 +913,9 @@ OvsDeviceControl(PDEVICE_OBJECT deviceObject, status = InvokeNetlinkCmdHandler(&usrParamsCtx, nlFamilyOps, &replyLen); done: + OvsReleaseSwitchContext(gOvsSwitchContext); + +exit: KeMemoryBarrier(); instance->inUse = 0; diff --git a/datapath-windows/ovsext/Switch.c b/datapath-windows/ovsext/Switch.c index 61a453183..4f4591fca 100644 --- a/datapath-windows/ovsext/Switch.c +++ b/datapath-windows/ovsext/Switch.c @@ -42,6 +42,12 @@ extern PNDIS_SPIN_LOCK gOvsCtrlLock; extern NDIS_HANDLE gOvsExtDriverHandle; extern NDIS_HANDLE gOvsExtDriverObject; +/* + * Reference count used to prevent premature deallocation of the global switch + * context structure, gOvsSwitchContext. + */ +volatile LONG gOvsSwitchContextRefCount = 1; + static NDIS_STATUS OvsCreateSwitch(NDIS_HANDLE ndisFilterHandle, POVS_SWITCH_CONTEXT *switchContextOut); static NDIS_STATUS OvsInitSwitchContext(POVS_SWITCH_CONTEXT switchContext); @@ -423,6 +429,7 @@ OvsInitSwitchContext(POVS_SWITCH_CONTEXT switchContext) switchContext->isActivateFailed = FALSE; switchContext->dpNo = OVS_DP_NUMBER; ovsTimeIncrementPerTick = KeQueryTimeIncrement() / 10000; + OVS_LOG_TRACE("Exit: Succesfully initialized switchContext: %p", switchContext); return NDIS_STATUS_SUCCESS; @@ -430,6 +437,12 @@ OvsInitSwitchContext(POVS_SWITCH_CONTEXT switchContext) static VOID OvsUninitSwitchContext(POVS_SWITCH_CONTEXT switchContext) +{ + OvsReleaseSwitchContext(switchContext); +} + +VOID +OvsDeleteSwitchContext(POVS_SWITCH_CONTEXT switchContext) { OVS_LOG_TRACE("Enter: Delete switchContext:%p", switchContext); @@ -457,6 +470,49 @@ OvsUninitSwitchContext(POVS_SWITCH_CONTEXT switchContext) OVS_LOG_TRACE("Exit: Delete switchContext: %p", switchContext); } +VOID +OvsReleaseSwitchContext(POVS_SWITCH_CONTEXT switchContext) +{ + LONG ref = 0; + LONG newRef = 0; + LONG icxRef = 0; + + do { + ref = gOvsSwitchContextRefCount; + newRef = (0 == ref) ? 0 : ref - 1; + icxRef = InterlockedCompareExchange(&gOvsSwitchContextRefCount, + newRef, + ref); + } while (icxRef != ref); + + if (ref == 1) { + OvsDeleteSwitchContext(switchContext); + } +} + +BOOLEAN +OvsAcquireSwitchContext(VOID) +{ + LONG ref = 0; + LONG newRef = 0; + LONG icxRef = 0; + BOOLEAN ret = FALSE; + + do { + ref = gOvsSwitchContextRefCount; + newRef = (0 == ref) ? 0 : ref + 1; + icxRef = InterlockedCompareExchange(&gOvsSwitchContextRefCount, + newRef, + ref); + } while (icxRef != ref); + + if (ref != 0) { + ret = TRUE; + } + + return ret; +} + /* * -------------------------------------------------------------------------- * This function activates the switch by initializing it with all the runtime diff --git a/datapath-windows/ovsext/Switch.h b/datapath-windows/ovsext/Switch.h index 796007254..6ec34e1f4 100644 --- a/datapath-windows/ovsext/Switch.h +++ b/datapath-windows/ovsext/Switch.h @@ -202,7 +202,6 @@ OvsAcquireDatapathWrite(OVS_DATAPATH *datapath, dispatch ? NDIS_RWL_AT_DISPATCH_LEVEL : 0); } - static __inline VOID OvsReleaseDatapath(OVS_DATAPATH *datapath, LOCK_STATE_EX *lockState) @@ -211,6 +210,11 @@ OvsReleaseDatapath(OVS_DATAPATH *datapath, NdisReleaseRWLock(datapath->lock, lockState); } +BOOLEAN +OvsAcquireSwitchContext(VOID); + +VOID +OvsReleaseSwitchContext(POVS_SWITCH_CONTEXT switchContext); PVOID OvsGetExternalVport(); -- cgit v1.2.1 From 6625245743a8621a8eee1fd67add15120ed042f8 Mon Sep 17 00:00:00 2001 From: Jesse Gross Date: Fri, 27 Mar 2015 07:39:18 -0700 Subject: tunneling: Include IP TTL in flow metadata. The IP TTL is currently omitted in the extracted tunnel information that is stored in the flow for userspace tunneling. This includes it so that the same logic used by the kernel also applies. Signed-off-by: Jesse Gross Acked-by: Pritesh Kothari Acked-by: Pravin B Shelar --- lib/netdev-vport.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c index 211edc732..d4de0d1f1 100644 --- a/lib/netdev-vport.c +++ b/lib/netdev-vport.c @@ -842,6 +842,7 @@ ip_extract_tnl_md(struct dp_packet *packet, struct flow_tnl *tnl) tnl->ip_src = get_16aligned_be32(&nh->ip_src); tnl->ip_dst = get_16aligned_be32(&nh->ip_dst); tnl->ip_tos = nh->ip_tos; + tnl->ip_ttl = nh->ip_ttl; return l4; } -- cgit v1.2.1 From 6432e527ce4bc1d67b8fe8ec111817b52953b7c3 Mon Sep 17 00:00:00 2001 From: Jesse Gross Date: Thu, 26 Mar 2015 16:53:39 -0700 Subject: tunneling: Add check for GRE protocol is Ethernet. On receive, the userspace GRE code doesn't check the protocol field. Since OVS only understands Ethernet packets, this adds a check that the inner protocol is Ethernet and discards other types of packets. Signed-off-by: Jesse Gross Acked-by: Pritesh Kothari Acked-by: Pravin B Shelar --- lib/netdev-vport.c | 4 ++++ tests/tunnel-push-pop.at | 16 ++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c index d4de0d1f1..1ee68bcc1 100644 --- a/lib/netdev-vport.c +++ b/lib/netdev-vport.c @@ -911,6 +911,10 @@ parse_gre_header(struct dp_packet *packet, return -EINVAL; } + if (greh->protocol != htons(ETH_TYPE_TEB)) { + return -EINVAL; + } + hlen = gre_header_len(greh->flags); if (hlen > dp_packet_size(packet)) { return -EINVAL; diff --git a/tests/tunnel-push-pop.at b/tests/tunnel-push-pop.at index 6e1c0c116..ee17a2fc1 100644 --- a/tests/tunnel-push-pop.at +++ b/tests/tunnel-push-pop.at @@ -75,5 +75,21 @@ AT_CHECK([tail -1 stdout], [0], [Datapath actions: tnl_push(tnl_port(3),header(size=42,type=3,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x40),gre((flags=0x20,proto=0x6558),key=0x1c8)),out_port(100)) ]) +dnl Check decapsulation of GRE packet +AT_CHECK([ovs-appctl netdev-dummy/receive p0 '001b213cac30001b213cab6408004500007e79464000402f99080101025c0101025820006558000001c8fe71d883724fbeb6f4e1494a080045000054ba200000400184861e0000011e00000200004227e75400030af3195500000000f265010000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637']) +ovs-appctl time/warp 1000 + +AT_CHECK([ovs-ofctl dump-ports int-br | grep 'port 3'], [0], [dnl + port 3: rx pkts=1, bytes=98, drop=0, errs=0, frame=0, over=0, crc=0 +]) + +dnl Check GRE only accepts encapsulated Ethernet frames +AT_CHECK([ovs-appctl netdev-dummy/receive p0 '001b213cac30001b213cab6408004500007e79464000402f99080101025c0101025820000800000001c8fe71d883724fbeb6f4e1494a080045000054ba200000400184861e0000011e00000200004227e75400030af3195500000000f265010000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637']) +ovs-appctl time/warp 1000 + +AT_CHECK([ovs-ofctl dump-ports int-br | grep 'port 3'], [0], [dnl + port 3: rx pkts=1, bytes=98, drop=0, errs=0, frame=0, over=0, crc=0 +]) + OVS_VSWITCHD_STOP AT_CLEANUP -- cgit v1.2.1 From d804d31e24a47d51bf066052c87524ed865f3f4a Mon Sep 17 00:00:00 2001 From: Jesse Gross Date: Thu, 26 Mar 2015 17:09:38 -0700 Subject: tunneling: Fix location of GRE checksums. The GRE checksum is a 16 bit field stored in a 32 bit option (the rest is reserved). The current code treats the checksum as a 32-bit field and places it in the right place for little endian systems but not big endian. This fixes the problem by storing the 16 bit field directly. Signed-off-by: Jesse Gross Acked-by: Pritesh Kothari Acked-by: Pravin B Shelar --- lib/netdev-vport.c | 6 ++---- lib/odp-util.c | 10 ++++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c index 1ee68bcc1..a9639d3c3 100644 --- a/lib/netdev-vport.c +++ b/lib/netdev-vport.c @@ -996,10 +996,8 @@ netdev_gre_push_header__(struct dp_packet *packet, greh = push_ip_header(packet, header, size, &ip_tot_size); if (greh->flags & htons(GRE_CSUM)) { - ovs_16aligned_be32 *options = (ovs_16aligned_be32 *) (greh + 1); - - put_16aligned_be32(options, - (OVS_FORCE ovs_be32) csum(greh, ip_tot_size - sizeof (struct ip_header))); + ovs_be16 *csum_opt = (ovs_be16 *) (greh + 1); + *csum_opt = csum(greh, ip_tot_size - sizeof (struct ip_header)); } } diff --git a/lib/odp-util.c b/lib/odp-util.c index 827b91c6e..b2e5319c5 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -565,7 +565,7 @@ format_odp_tnl_push_header(struct ds *ds, struct ovs_action_push_tnl *data) greh->flags, ntohs(greh->protocol)); options = (ovs_16aligned_be32 *)(greh + 1); if (greh->flags & htons(GRE_CSUM)) { - ds_put_format(ds, ",csum=0x%"PRIx32, ntohl(get_16aligned_be32(options))); + ds_put_format(ds, ",csum=0x%"PRIx16, ntohs(*((ovs_be16 *)options))); options++; } if (greh->flags & htons(GRE_KEY)) { @@ -913,12 +913,14 @@ ovs_parse_tnl_push(const char *s, struct ovs_action_push_tnl *data) ovs_16aligned_be32 *options = (ovs_16aligned_be32 *) (greh + 1); if (greh->flags & htons(GRE_CSUM)) { - uint32_t csum; + uint16_t csum; - if (!ovs_scan_len(s, &n, ",csum=0x%"SCNx32, &csum)) { + if (!ovs_scan_len(s, &n, ",csum=0x%"SCNx16, &csum)) { return -EINVAL; } - put_16aligned_be32(options, htonl(csum)); + + memset(options, 0, sizeof *options); + *((ovs_be16 *)options) = htons(csum); options++; } if (greh->flags & htons(GRE_KEY)) { -- cgit v1.2.1 From 61cf6b70243ee5bb7e948cabf5298a21a66e7c77 Mon Sep 17 00:00:00 2001 From: Jesse Gross Date: Thu, 26 Mar 2015 22:55:53 -0700 Subject: tunneling: Use flow flag for GRE checksum calculation. The indication to calculate the GRE checksum is currently the port config rather than the tunnel flow. Currently there is a one to one mapping between the two so there is no difference. However, the kernel datapath must use the flow and it is also potentially more flexible, so this switches how we decide whether to calculate the checksum. Signed-off-by: Jesse Gross Acked-by: Pritesh Kothari Acked-by: Pravin B Shelar --- lib/netdev-vport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c index a9639d3c3..0e0d79145 100644 --- a/lib/netdev-vport.c +++ b/lib/netdev-vport.c @@ -1040,7 +1040,7 @@ netdev_gre_build_header(const struct netdev *netdev, greh->flags = 0; options = (ovs_16aligned_be32 *) (greh + 1); - if (tnl_cfg->csum) { + if (tnl_flow->tunnel.flags & FLOW_TNL_F_CSUM) { greh->flags |= htons(GRE_CSUM); put_16aligned_be32(options, 0); options++; -- cgit v1.2.1 From a92a3aae09f6f9c169d65486b9053292844ca5f2 Mon Sep 17 00:00:00 2001 From: Jesse Gross Date: Fri, 27 Mar 2015 17:51:35 -0700 Subject: odp-util: Shift VXLAN VNI when printing/parsing. Currently when printing a userspace tunnel action for VXLAN, the VNI is treated as a 32 bit field rather than 24 bit. Even if this is the representation that we use internally, we should still show the right VNI to avoid confusing people. Signed-off-by: Jesse Gross Acked-by: Pritesh Kothari Acked-by: Pravin B Shelar --- lib/odp-util.c | 4 ++-- tests/odp.at | 2 +- tests/tunnel-push-pop.at | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/odp-util.c b/lib/odp-util.c index b2e5319c5..6b03d9d09 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -552,7 +552,7 @@ format_odp_tnl_push_header(struct ds *ds, struct ovs_action_push_tnl *data) vxh = (const struct vxlanhdr *) (udp + 1); ds_put_format(ds, "vxlan(flags=0x%"PRIx32",vni=0x%"PRIx32")", ntohl(get_16aligned_be32(&vxh->vx_flags)), - ntohl(get_16aligned_be32(&vxh->vx_vni))); + ntohl(get_16aligned_be32(&vxh->vx_vni)) >> 8); } else if (data->tnl_type == OVS_VPORT_TYPE_GRE) { const struct gre_base_hdr *greh; ovs_16aligned_be32 *options; @@ -901,7 +901,7 @@ ovs_parse_tnl_push(const char *s, struct ovs_action_push_tnl *data) return -EINVAL; } put_16aligned_be32(&vxh->vx_flags, htonl(vx_flags)); - put_16aligned_be32(&vxh->vx_vni, htonl(vx_vni)); + put_16aligned_be32(&vxh->vx_vni, htonl(vx_vni << 8)); tnl_type = OVS_VPORT_TYPE_VXLAN; header_len = sizeof *eth + sizeof *ip + sizeof *udp + sizeof *vxh; diff --git a/tests/odp.at b/tests/odp.at index de08771d2..bc68d35d4 100644 --- a/tests/odp.at +++ b/tests/odp.at @@ -281,7 +281,7 @@ set(tunnel(tun_id=0xabcdef1234567890,src=1.1.1.1,dst=2.2.2.2,tos=0,ttl=64,tp_src tnl_pop(4) tnl_push(tnl_port(4),header(size=42,type=3,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x40),gre((flags=0x20,proto=0x6558),key=0x1e241)),out_port(1)) tnl_push(tnl_port(4),header(size=46,type=3,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x40),gre((flags=0xa0,proto=0x6558),csum=0x0,key=0x1e241)),out_port(1)) -tnl_push(tnl_port(6),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=4789),vxlan(flags=0x8000000,vni=0x1c700)),out_port(1)) +tnl_push(tnl_port(6),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=4789),vxlan(flags=0x8000000,vni=0x1c7)),out_port(1)) ]) AT_CHECK_UNQUOTED([ovstest test-odp parse-actions < actions.txt], [0], [`cat actions.txt` diff --git a/tests/tunnel-push-pop.at b/tests/tunnel-push-pop.at index ee17a2fc1..3c3f5d874 100644 --- a/tests/tunnel-push-pop.at +++ b/tests/tunnel-push-pop.at @@ -58,14 +58,14 @@ dnl Check VXLAN tunnel push AT_CHECK([ovs-ofctl add-flow int-br action=2]) AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout]) AT_CHECK([tail -1 stdout], [0], - [Datapath actions: tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=4789),vxlan(flags=0x8000000,vni=0x7b00)),out_port(100)) + [Datapath actions: tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=4789),vxlan(flags=0x8000000,vni=0x7b)),out_port(100)) ]) dnl Check VXLAN tunnel push set tunnel id by flow AT_CHECK([ovs-ofctl add-flow int-br "actions=set_tunnel:124,4"]) AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout]) AT_CHECK([tail -1 stdout], [0], - [Datapath actions: tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b7,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.93,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=4789),vxlan(flags=0x8000000,vni=0x7c00)),out_port(100)) + [Datapath actions: tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b7,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.93,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=4789),vxlan(flags=0x8000000,vni=0x7c)),out_port(100)) ]) dnl Check GRE tunnel push -- cgit v1.2.1 From 83fbb69b50325ad01604d035dbcf6c5fdd61d564 Mon Sep 17 00:00:00 2001 From: Jesse Gross Date: Tue, 7 Apr 2015 16:40:18 -0700 Subject: vxlan: Set FLOW_TNL_F_KEY for received packets. The VNI is always present in the VXLAN header, so we should set the FLOW_TNL_F_KEY flag to indicate this. However, the userspace implementation of VXLAN currently does not. Signed-off-by: Jesse Gross --- lib/netdev-vport.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c index 0e0d79145..c207cea44 100644 --- a/lib/netdev-vport.c +++ b/lib/netdev-vport.c @@ -1093,6 +1093,7 @@ vxlan_extract_md(struct dp_packet *packet) tnl->tp_src = udp->udp_src; tnl->tp_dst = udp->udp_dst; tnl->tun_id = htonll(ntohl(get_16aligned_be32(&vxh->vx_vni)) >> 8); + tnl->flags |= FLOW_TNL_F_KEY; dp_packet_reset_packet(packet, VXLAN_HLEN); } -- cgit v1.2.1 From e066f78fea7ba17d293f97c51cd15d69d2c75dbf Mon Sep 17 00:00:00 2001 From: Jesse Gross Date: Thu, 26 Mar 2015 12:07:02 -0700 Subject: tunneling: Factor out common UDP tunnel code. Currently, the userspace VXLAN implementation contains the code for generating and parsing both the UDP and VXLAN headers. This pulls out the UDP portion for better layering and to make it easier to support additional UDP based tunnels and features. Signed-off-by: Jesse Gross Acked-by: Pravin B Shelar --- lib/netdev-vport.c | 105 ++++++++++++++++++++++++++++++++--------------------- lib/odp-util.c | 37 +++++++++++-------- 2 files changed, 85 insertions(+), 57 deletions(-) diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c index c207cea44..4d0c3fb6e 100644 --- a/lib/netdev-vport.c +++ b/lib/netdev-vport.c @@ -876,6 +876,65 @@ push_ip_header(struct dp_packet *packet, return ip + 1; } +static void * +udp_extract_tnl_md(struct dp_packet *packet, struct flow_tnl *tnl) +{ + struct udp_header *udp; + + udp = ip_extract_tnl_md(packet, tnl); + if (!udp) { + return NULL; + } + + tnl->tp_src = udp->udp_src; + tnl->tp_dst = udp->udp_dst; + + return udp + 1; +} + +static ovs_be16 +get_src_port(struct dp_packet *packet) +{ + uint32_t hash; + + hash = dp_packet_get_dp_hash(packet); + + return htons((((uint64_t) hash * (tnl_udp_port_max - tnl_udp_port_min)) >> 32) + + tnl_udp_port_min); +} + +static void * +push_udp_header(struct dp_packet *packet, const void *header, int size) +{ + struct udp_header *udp; + int ip_tot_size; + + udp = push_ip_header(packet, header, size, &ip_tot_size); + + /* set udp src port */ + udp->udp_src = get_src_port(packet); + udp->udp_len = htons(ip_tot_size - sizeof (struct ip_header)); + /* udp_csum is zero */ + + return udp + 1; +} + +static void * +udp_build_header(struct netdev_tunnel_config *tnl_cfg, + struct ovs_action_push_tnl *data) +{ + struct ip_header *ip; + struct udp_header *udp; + + ip = ip_hdr(data->header); + ip->ip_proto = IPPROTO_UDP; + + udp = (struct udp_header *) (ip + 1); + udp->udp_dst = tnl_cfg->dst_port; + + return udp + 1; +} + static int gre_header_len(ovs_be16 flags) { @@ -1068,7 +1127,6 @@ vxlan_extract_md(struct dp_packet *packet) { struct pkt_metadata *md = &packet->md; struct flow_tnl *tnl = &md->tunnel; - struct udp_header *udp; struct vxlanhdr *vxh; memset(md, 0, sizeof *md); @@ -1076,11 +1134,10 @@ vxlan_extract_md(struct dp_packet *packet) return; } - udp = ip_extract_tnl_md(packet, tnl); - if (!udp) { + vxh = udp_extract_tnl_md(packet, tnl); + if (!vxh) { return; } - vxh = (struct vxlanhdr *) (udp + 1); if (get_16aligned_be32(&vxh->vx_flags) != htonl(VXLAN_FLAGS) || (get_16aligned_be32(&vxh->vx_vni) & htonl(0xff))) { @@ -1090,8 +1147,6 @@ vxlan_extract_md(struct dp_packet *packet) reset_tnl_md(md); return; } - tnl->tp_src = udp->udp_src; - tnl->tp_dst = udp->udp_dst; tnl->tun_id = htonll(ntohl(get_16aligned_be32(&vxh->vx_vni)) >> 8); tnl->flags |= FLOW_TNL_F_KEY; @@ -1117,21 +1172,14 @@ netdev_vxlan_build_header(const struct netdev *netdev, { struct netdev_vport *dev = netdev_vport_cast(netdev); struct netdev_tunnel_config *tnl_cfg; - struct ip_header *ip; - struct udp_header *udp; struct vxlanhdr *vxh; /* XXX: RCUfy tnl_cfg. */ ovs_mutex_lock(&dev->mutex); tnl_cfg = &dev->tnl_cfg; - ip = ip_hdr(data->header); - ip->ip_proto = IPPROTO_UDP; + vxh = udp_build_header(tnl_cfg, data); - udp = (struct udp_header *) (ip + 1); - udp->udp_dst = tnl_cfg->dst_port; - - vxh = (struct vxlanhdr *) (udp + 1); put_16aligned_be32(&vxh->vx_flags, htonl(VXLAN_FLAGS)); put_16aligned_be32(&vxh->vx_vni, htonl(ntohll(tnl_flow->tunnel.tun_id) << 8)); @@ -1141,32 +1189,6 @@ netdev_vxlan_build_header(const struct netdev *netdev, return 0; } -static ovs_be16 -get_src_port(struct dp_packet *packet) -{ - uint32_t hash; - - hash = dp_packet_get_dp_hash(packet); - - return htons((((uint64_t) hash * (tnl_udp_port_max - tnl_udp_port_min)) >> 32) + - tnl_udp_port_min); -} - -static void -netdev_vxlan_push_header__(struct dp_packet *packet, - const void *header, int size) -{ - struct udp_header *udp; - int ip_tot_size; - - udp = push_ip_header(packet, header, size, &ip_tot_size); - - /* set udp src port */ - udp->udp_src = get_src_port(packet); - udp->udp_len = htons(ip_tot_size - sizeof (struct ip_header)); - /* udp_csum is zero */ -} - static int netdev_vxlan_push_header(const struct netdev *netdev OVS_UNUSED, struct dp_packet **packets, int cnt, @@ -1175,8 +1197,7 @@ netdev_vxlan_push_header(const struct netdev *netdev OVS_UNUSED, int i; for (i = 0; i < cnt; i++) { - netdev_vxlan_push_header__(packets[i], - data->header, VXLAN_HLEN); + push_udp_header(packets[i], data->header, VXLAN_HLEN); packets[i]->md = PKT_METADATA_INITIALIZER(u32_to_odp(data->out_port)); } return 0; diff --git a/lib/odp-util.c b/lib/odp-util.c index 6b03d9d09..e944c8505 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -510,6 +510,18 @@ format_odp_hash_action(struct ds *ds, const struct ovs_action_hash *hash_act) ds_put_format(ds, ")"); } +static const void * +format_udp_tnl_push_header(struct ds *ds, const struct ip_header *ip) +{ + const struct udp_header *udp; + + udp = (const struct udp_header *) (ip + 1); + ds_put_format(ds, "udp(src=%"PRIu16",dst=%"PRIu16"),", + ntohs(udp->udp_src), ntohs(udp->udp_dst)); + + return udp + 1; +} + static void format_odp_tnl_push_header(struct ds *ds, struct ovs_action_push_tnl *data) { @@ -541,15 +553,9 @@ format_odp_tnl_push_header(struct ds *ds, struct ovs_action_push_tnl *data) if (data->tnl_type == OVS_VPORT_TYPE_VXLAN) { const struct vxlanhdr *vxh; - const struct udp_header *udp; - /* UDP */ - udp = (const struct udp_header *) (ip + 1); - ds_put_format(ds, "udp(src=%"PRIu16",dst=%"PRIu16"),", - ntohs(udp->udp_src), ntohs(udp->udp_dst)); + vxh = format_udp_tnl_push_header(ds, ip); - /* VxLan */ - vxh = (const struct vxlanhdr *) (udp + 1); ds_put_format(ds, "vxlan(flags=0x%"PRIx32",vni=0x%"PRIx32")", ntohl(get_16aligned_be32(&vxh->vx_flags)), ntohl(get_16aligned_be32(&vxh->vx_vni)) >> 8); @@ -887,7 +893,6 @@ ovs_parse_tnl_push(const char *s, struct ovs_action_push_tnl *data) greh = (struct gre_base_hdr *) l4; if (ovs_scan_len(s, &n, "udp(src=%"SCNi16",dst=%"SCNi16"),", &udp_src, &udp_dst)) { - struct vxlanhdr *vxh; uint32_t vx_flags, vx_vni; udp->udp_src = htons(udp_src); @@ -895,16 +900,18 @@ ovs_parse_tnl_push(const char *s, struct ovs_action_push_tnl *data) udp->udp_len = 0; udp->udp_csum = 0; - vxh = (struct vxlanhdr *) (udp + 1); - if (!ovs_scan_len(s, &n, "vxlan(flags=0x%"SCNx32",vni=0x%"SCNx32"))", + if (ovs_scan_len(s, &n, "vxlan(flags=0x%"SCNx32",vni=0x%"SCNx32"))", &vx_flags, &vx_vni)) { + struct vxlanhdr *vxh = (struct vxlanhdr *) (udp + 1); + + put_16aligned_be32(&vxh->vx_flags, htonl(vx_flags)); + put_16aligned_be32(&vxh->vx_vni, htonl(vx_vni << 8)); + tnl_type = OVS_VPORT_TYPE_VXLAN; + header_len = sizeof *eth + sizeof *ip + + sizeof *udp + sizeof *vxh; + } else { return -EINVAL; } - put_16aligned_be32(&vxh->vx_flags, htonl(vx_flags)); - put_16aligned_be32(&vxh->vx_vni, htonl(vx_vni << 8)); - tnl_type = OVS_VPORT_TYPE_VXLAN; - header_len = sizeof *eth + sizeof *ip + - sizeof *udp + sizeof *vxh; } else if (ovs_scan_len(s, &n, "gre((flags=0x%"SCNx16",proto=0x%"SCNx16")", &greh->flags, &gre_proto)){ -- cgit v1.2.1 From e5a1caeed45ae4dc8783a2fc1ea466c9e1cc79a7 Mon Sep 17 00:00:00 2001 From: Jesse Gross Date: Thu, 26 Mar 2015 13:51:06 -0700 Subject: tunneling: Add userspace tunnel support for Geneve. This adds basic userspace dataplane support for the Geneve tunneling protocol. The rest of userspace only has the ability to handle Geneve without options and this follows that pattern for the time being. However, when the rest of userspace is updated it should be easy to extend the dataplane as well. Signed-off-by: Jesse Gross Acked-by: Pravin B Shelar --- NEWS | 4 +- lib/netdev-vport.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++- lib/odp-util.c | 28 ++++++++++-- lib/packets.h | 19 ++++++++ tests/odp.at | 1 + tests/tunnel-push-pop.at | 16 +++++++ 6 files changed, 177 insertions(+), 6 deletions(-) diff --git a/NEWS b/NEWS index 9f9dc4ce2..87460a712 100644 --- a/NEWS +++ b/NEWS @@ -62,8 +62,8 @@ Post-v2.3.0 - A simple wrapper script, 'ovs-docker', to integrate OVS with Docker containers. If and when there is a native integration of Open vSwitch with Docker, the wrapper script will be retired. - - Added support for DPDK Tunneling. VXLAN and GRE are supported protocols. - This is generic tunneling mechanism for userspace datapath. + - Added support for DPDK Tunneling. VXLAN, GRE, and Geneve are supported + protocols. This is generic tunneling mechanism for userspace datapath. - Support for multicast snooping (IGMPv1 and IGMPv2) - Support for Linux kernels up to 3.19.x - The documentation now use the term 'destination' to mean one of syslog, diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c index 4d0c3fb6e..ed407dcb0 100644 --- a/lib/netdev-vport.c +++ b/lib/netdev-vport.c @@ -61,6 +61,11 @@ static struct vlog_rate_limit err_rl = VLOG_RATE_LIMIT_INIT(60, 5); sizeof(struct udp_header) + \ sizeof(struct vxlanhdr)) +#define GENEVE_BASE_HLEN (sizeof(struct eth_header) + \ + sizeof(struct ip_header) + \ + sizeof(struct udp_header) + \ + sizeof(struct genevehdr)) + #define DEFAULT_TTL 64 struct netdev_vport { @@ -1203,6 +1208,112 @@ netdev_vxlan_push_header(const struct netdev *netdev OVS_UNUSED, return 0; } +static void +geneve_extract_md(struct dp_packet *packet) +{ + struct pkt_metadata *md = &packet->md; + struct flow_tnl *tnl = &md->tunnel; + struct genevehdr *gnh; + unsigned int hlen; + + memset(md, 0, sizeof *md); + if (GENEVE_BASE_HLEN > dp_packet_size(packet)) { + VLOG_WARN_RL(&err_rl, "geneve packet too small: min header=%u packet size=%u\n", + (unsigned int)GENEVE_BASE_HLEN, dp_packet_size(packet)); + return; + } + + gnh = udp_extract_tnl_md(packet, tnl); + if (!gnh) { + return; + } + + hlen = GENEVE_BASE_HLEN + gnh->opt_len * 4; + if (hlen > dp_packet_size(packet)) { + VLOG_WARN_RL(&err_rl, "geneve packet too small: header len=%u packet size=%u\n", + hlen, dp_packet_size(packet)); + reset_tnl_md(md); + return; + } + + if (gnh->ver != 0) { + VLOG_WARN_RL(&err_rl, "unknown geneve version: %"PRIu8"\n", gnh->ver); + reset_tnl_md(md); + return; + } + + if (gnh->opt_len && gnh->critical) { + VLOG_WARN_RL(&err_rl, "unknown geneve critical options: %"PRIu8" bytes\n", + gnh->opt_len * 4); + reset_tnl_md(md); + return; + } + + if (gnh->proto_type != htons(ETH_TYPE_TEB)) { + VLOG_WARN_RL(&err_rl, "unknown geneve encapsulated protocol: %#x\n", + ntohs(gnh->proto_type)); + reset_tnl_md(md); + return; + } + + tnl->flags |= gnh->oam ? FLOW_TNL_F_OAM : 0; + tnl->tun_id = htonll(ntohl(get_16aligned_be32(&gnh->vni)) >> 8); + tnl->flags |= FLOW_TNL_F_KEY; + + dp_packet_reset_packet(packet, hlen); +} + +static int +netdev_geneve_pop_header(struct netdev *netdev_ OVS_UNUSED, + struct dp_packet **pkt, int cnt) +{ + int i; + + for (i = 0; i < cnt; i++) { + geneve_extract_md(pkt[i]); + } + return 0; +} + +static int +netdev_geneve_build_header(const struct netdev *netdev, + struct ovs_action_push_tnl *data, + const struct flow *tnl_flow) +{ + struct netdev_vport *dev = netdev_vport_cast(netdev); + struct netdev_tunnel_config *tnl_cfg; + struct genevehdr *gnh; + + /* XXX: RCUfy tnl_cfg. */ + ovs_mutex_lock(&dev->mutex); + tnl_cfg = &dev->tnl_cfg; + + gnh = udp_build_header(tnl_cfg, data); + + gnh->oam = !!(tnl_flow->tunnel.flags & FLOW_TNL_F_OAM); + gnh->proto_type = htons(ETH_TYPE_TEB); + put_16aligned_be32(&gnh->vni, htonl(ntohll(tnl_flow->tunnel.tun_id) << 8)); + + ovs_mutex_unlock(&dev->mutex); + data->header_len = GENEVE_BASE_HLEN; + data->tnl_type = OVS_VPORT_TYPE_GENEVE; + return 0; +} + +static int +netdev_geneve_push_header(const struct netdev *netdev OVS_UNUSED, + struct dp_packet **packets, int cnt, + const struct ovs_action_push_tnl *data) +{ + int i; + + for (i = 0; i < cnt; i++) { + push_udp_header(packets[i], data->header, data->header_len); + packets[i]->md = PKT_METADATA_INITIALIZER(u32_to_odp(data->out_port)); + } + return 0; +} + static void netdev_vport_range(struct unixctl_conn *conn, int argc, const char *argv[], void *aux OVS_UNUSED) @@ -1332,7 +1443,9 @@ netdev_vport_tunnel_register(void) /* The name of the dpif_port should be short enough to accomodate adding * a port number to the end if one is necessary. */ static const struct vport_class vport_classes[] = { - TUNNEL_CLASS("geneve", "genev_sys", NULL, NULL, NULL), + TUNNEL_CLASS("geneve", "genev_sys", netdev_geneve_build_header, + netdev_geneve_push_header, + netdev_geneve_pop_header), TUNNEL_CLASS("gre", "gre_sys", netdev_gre_build_header, netdev_gre_push_header, netdev_gre_pop_header), diff --git a/lib/odp-util.c b/lib/odp-util.c index e944c8505..4e6a06d1c 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -559,6 +559,14 @@ format_odp_tnl_push_header(struct ds *ds, struct ovs_action_push_tnl *data) ds_put_format(ds, "vxlan(flags=0x%"PRIx32",vni=0x%"PRIx32")", ntohl(get_16aligned_be32(&vxh->vx_flags)), ntohl(get_16aligned_be32(&vxh->vx_vni)) >> 8); + } else if (data->tnl_type == OVS_VPORT_TYPE_GENEVE) { + const struct genevehdr *gnh; + + gnh = format_udp_tnl_push_header(ds, ip); + + ds_put_format(ds, "geneve(%svni=0x%"PRIx32")", + gnh->oam ? "oam," : "", + ntohl(get_16aligned_be32(&gnh->vni)) >> 8); } else if (data->tnl_type == OVS_VPORT_TYPE_GRE) { const struct gre_base_hdr *greh; ovs_16aligned_be32 *options; @@ -893,7 +901,7 @@ ovs_parse_tnl_push(const char *s, struct ovs_action_push_tnl *data) greh = (struct gre_base_hdr *) l4; if (ovs_scan_len(s, &n, "udp(src=%"SCNi16",dst=%"SCNi16"),", &udp_src, &udp_dst)) { - uint32_t vx_flags, vx_vni; + uint32_t vx_flags, vni; udp->udp_src = htons(udp_src); udp->udp_dst = htons(udp_dst); @@ -901,14 +909,28 @@ ovs_parse_tnl_push(const char *s, struct ovs_action_push_tnl *data) udp->udp_csum = 0; if (ovs_scan_len(s, &n, "vxlan(flags=0x%"SCNx32",vni=0x%"SCNx32"))", - &vx_flags, &vx_vni)) { + &vx_flags, &vni)) { struct vxlanhdr *vxh = (struct vxlanhdr *) (udp + 1); put_16aligned_be32(&vxh->vx_flags, htonl(vx_flags)); - put_16aligned_be32(&vxh->vx_vni, htonl(vx_vni << 8)); + put_16aligned_be32(&vxh->vx_vni, htonl(vni << 8)); tnl_type = OVS_VPORT_TYPE_VXLAN; header_len = sizeof *eth + sizeof *ip + sizeof *udp + sizeof *vxh; + } else if (ovs_scan_len(s, &n, "geneve(")) { + struct genevehdr *gnh = (struct genevehdr *) (udp + 1); + + if (ovs_scan_len(s, &n, "oam,")) { + gnh->oam = 1; + } + if (!ovs_scan_len(s, &n, "vni=0x%"SCNx32"))", &vni)) { + return -EINVAL; + } + gnh->proto_type = htons(ETH_TYPE_TEB); + put_16aligned_be32(&gnh->vni, htonl(vni << 8)); + tnl_type = OVS_VPORT_TYPE_GENEVE; + header_len = sizeof *eth + sizeof *ip + + sizeof *udp + sizeof *gnh; } else { return -EINVAL; } diff --git a/lib/packets.h b/lib/packets.h index e80de6bc6..2bbe6d9e9 100644 --- a/lib/packets.h +++ b/lib/packets.h @@ -733,6 +733,25 @@ struct geneve_opt { uint8_t opt_data[]; }; +struct genevehdr { +#ifdef WORDS_BIGENDIAN + uint8_t ver:2; + uint8_t opt_len:6; + uint8_t oam:1; + uint8_t critical:1; + uint8_t rsvd1:6; +#else + uint8_t opt_len:6; + uint8_t ver:2; + uint8_t rsvd1:6; + uint8_t critical:1; + uint8_t oam:1; +#endif + ovs_be16 proto_type; + ovs_16aligned_be32 vni; + struct geneve_opt options[]; +}; + /* GRE protocol header */ struct gre_base_hdr { ovs_be16 flags; diff --git a/tests/odp.at b/tests/odp.at index bc68d35d4..7fda4498a 100644 --- a/tests/odp.at +++ b/tests/odp.at @@ -282,6 +282,7 @@ tnl_pop(4) tnl_push(tnl_port(4),header(size=42,type=3,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x40),gre((flags=0x20,proto=0x6558),key=0x1e241)),out_port(1)) tnl_push(tnl_port(4),header(size=46,type=3,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x40),gre((flags=0xa0,proto=0x6558),csum=0x0,key=0x1e241)),out_port(1)) tnl_push(tnl_port(6),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=4789),vxlan(flags=0x8000000,vni=0x1c7)),out_port(1)) +tnl_push(tnl_port(6),header(size=50,type=5,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=6081),geneve(oam,vni=0x1c7)),out_port(1)) ]) AT_CHECK_UNQUOTED([ovstest test-odp parse-actions < actions.txt], [0], [`cat actions.txt` diff --git a/tests/tunnel-push-pop.at b/tests/tunnel-push-pop.at index 3c3f5d874..77dde69dd 100644 --- a/tests/tunnel-push-pop.at +++ b/tests/tunnel-push-pop.at @@ -10,6 +10,8 @@ AT_CHECK([ovs-vsctl add-port int-br t2 -- set Interface t2 type=vxlan \ options:remote_ip=1.1.2.92 options:key=456 ofport_request=3\ -- add-port int-br t3 -- set Interface t3 type=vxlan \ options:remote_ip=1.1.2.93 options:out_key=flow ofport_request=4\ + -- add-port int-br t4 -- set Interface t4 type=geneve \ + options:remote_ip=1.1.2.92 options:key=123 ofport_request=5\ ], [0]) AT_CHECK([ovs-appctl dpif/show], [0], [dnl @@ -22,6 +24,7 @@ dummy@ovs-dummy: hit:0 missed:0 t1 3/3: (gre: key=456, remote_ip=1.1.2.92) t2 2/4789: (vxlan: key=123, remote_ip=1.1.2.92) t3 4/4789: (vxlan: out_key=flow, remote_ip=1.1.2.93) + t4 5/6081: (geneve: key=123, remote_ip=1.1.2.92) ]) AT_CHECK([ovs-appctl ovs/route/add 1.1.2.92/24 br0], [0], [OK @@ -54,6 +57,12 @@ AT_CHECK([tail -1 stdout], [0], [Datapath actions: tnl_pop(3) ]) +dnl Check Geneve tunnel pop +AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=f8:bc:12:44:34:b6,dst=f8:bc:12:46:58:e0),eth_type(0x0800),ipv4(src=1.1.2.92,dst=1.1.2.88,proto=17,tos=0,ttl=64,frag=no),udp(src=51283,dst=6081)'], [0], [stdout]) +AT_CHECK([tail -1 stdout], [0], + [Datapath actions: tnl_pop(6081) +]) + dnl Check VXLAN tunnel push AT_CHECK([ovs-ofctl add-flow int-br action=2]) AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout]) @@ -75,6 +84,13 @@ AT_CHECK([tail -1 stdout], [0], [Datapath actions: tnl_push(tnl_port(3),header(size=42,type=3,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x40),gre((flags=0x20,proto=0x6558),key=0x1c8)),out_port(100)) ]) +dnl Check Geneve tunnel push +AT_CHECK([ovs-ofctl add-flow int-br action=5]) +AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout]) +AT_CHECK([tail -1 stdout], [0], + [Datapath actions: tnl_push(tnl_port(6081),header(size=50,type=5,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=6081,csum=0x0),geneve(vni=0x7b)),out_port(100)) +]) + dnl Check decapsulation of GRE packet AT_CHECK([ovs-appctl netdev-dummy/receive p0 '001b213cac30001b213cab6408004500007e79464000402f99080101025c0101025820006558000001c8fe71d883724fbeb6f4e1494a080045000054ba200000400184861e0000011e00000200004227e75400030af3195500000000f265010000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637']) ovs-appctl time/warp 1000 -- cgit v1.2.1 From 0292a0c9d99f6ec5980bd26a7094fc2a4148ebe8 Mon Sep 17 00:00:00 2001 From: Jesse Gross Date: Mon, 30 Mar 2015 12:17:05 -0700 Subject: packet: Add IP pseudoheader checksum calculation. As OVS adds userspace support for being the endpoint in protocols like tunnels, it will need to be able to calculate pseudoheaders as part of the checksum calculation. Signed-off-by: Jesse Gross Acked-by: Pravin B Shelar --- lib/packets.c | 14 ++++++++++++++ lib/packets.h | 1 + tests/library.at | 2 +- tests/test-csum.c | 31 +++++++++++++++++++++++++++++++ 4 files changed, 47 insertions(+), 1 deletion(-) diff --git a/lib/packets.c b/lib/packets.c index 07cf2eb24..419c6af49 100644 --- a/lib/packets.c +++ b/lib/packets.c @@ -1043,3 +1043,17 @@ compose_arp(struct dp_packet *b, const uint8_t eth_src[ETH_ADDR_LEN], dp_packet_set_frame(b, eth); dp_packet_set_l3(b, arp); } + +uint32_t +packet_csum_pseudoheader(const struct ip_header *ip) +{ + uint32_t partial = 0; + + partial = csum_add32(partial, get_16aligned_be32(&ip->ip_src)); + partial = csum_add32(partial, get_16aligned_be32(&ip->ip_dst)); + partial = csum_add16(partial, htons(ip->ip_proto)); + partial = csum_add16(partial, htons(ntohs(ip->ip_tot_len) - + IP_IHL(ip->ip_ihl_ver) * 4)); + + return partial; +} diff --git a/lib/packets.h b/lib/packets.h index 2bbe6d9e9..29ea54f0f 100644 --- a/lib/packets.h +++ b/lib/packets.h @@ -806,5 +806,6 @@ void packet_format_tcp_flags(struct ds *, uint16_t); const char *packet_tcp_flag_to_string(uint32_t flag); void compose_arp(struct dp_packet *b, const uint8_t eth_src[ETH_ADDR_LEN], ovs_be32 ip_src, ovs_be32 ip_dst); +uint32_t packet_csum_pseudoheader(const struct ip_header *); #endif /* packets.h */ diff --git a/tests/library.at b/tests/library.at index dfc5ad958..9bd6d81d5 100644 --- a/tests/library.at +++ b/tests/library.at @@ -7,7 +7,7 @@ AT_CHECK([ovstest test-flows flows pcap], [0], [checked 247 packets, 0 errors AT_CLEANUP AT_SETUP([test TCP/IP checksumming]) -AT_CHECK([ovstest test-csum], [0], [....#....#....###................................#................................# +AT_CHECK([ovstest test-csum], [0], [....#....#....####................................#................................# ]) AT_CLEANUP diff --git a/tests/test-csum.c b/tests/test-csum.c index e25fb3d67..2685f679c 100644 --- a/tests/test-csum.c +++ b/tests/test-csum.c @@ -20,11 +20,13 @@ #include #include #include +#include #include #include #include #include "crc32c.h" #include "ovstest.h" +#include "packets.h" #include "random.h" #include "unaligned.h" #include "util.h" @@ -175,6 +177,34 @@ test_crc32c(void) mark('#'); } +/* Check the IP pseudoheader calculation. */ +static void +test_pseudo(void) +{ + /* Try an IP header similar to one that the tunnel code + * might generate. */ + struct ip_header ip = { + .ip_ihl_ver = IP_IHL_VER(5, 4), + .ip_tos = 0, + .ip_tot_len = htons(134), + .ip_id = 0, + .ip_frag_off = htons(IP_DF), + .ip_ttl = 64, + .ip_proto = IPPROTO_UDP, + .ip_csum = htons(0x1265), + .ip_src = { .hi = htons(0x1400), .lo = htons(0x0002) }, + .ip_dst = { .hi = htons(0x1400), .lo = htons(0x0001) } + }; + + assert(packet_csum_pseudoheader(&ip) == 0x8628); + + /* And also test something totally different to check for + * corner cases. */ + memset(&ip, 0xff, sizeof ip); + assert(packet_csum_pseudoheader(&ip) == 0x5c2fb); + + mark('#'); +} static void test_csum_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) @@ -239,6 +269,7 @@ test_csum_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) test_rfc1624(); test_crc32c(); + test_pseudo(); /* Test recalc_csum16(). */ for (i = 0; i < 32; i++) { -- cgit v1.2.1 From 8e45fe7c9e20a068a879d8e39cf14c551b9d77ef Mon Sep 17 00:00:00 2001 From: Jesse Gross Date: Thu, 26 Mar 2015 14:27:19 -0700 Subject: tunneling: Add UDP checksum support for userspace tunnels. Kernel based OVS recently added the ability to support checksums for UDP based tunnels (Geneve and VXLAN). This adds similar support for the userspace datapath to bring feature parity. Signed-off-by: Jesse Gross Acked-by: Pravin B Shelar --- lib/netdev-vport.c | 37 ++++++++++++++++++++++++++++++++++--- lib/odp-util.c | 15 +++++++-------- tests/odp.at | 5 +++-- tests/tunnel-push-pop.at | 10 +++++----- 4 files changed, 49 insertions(+), 18 deletions(-) diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c index ed407dcb0..23483e3fe 100644 --- a/lib/netdev-vport.c +++ b/lib/netdev-vport.c @@ -891,6 +891,18 @@ udp_extract_tnl_md(struct dp_packet *packet, struct flow_tnl *tnl) return NULL; } + if (udp->udp_csum) { + uint32_t csum = packet_csum_pseudoheader(dp_packet_l3(packet)); + + csum = csum_continue(csum, udp, dp_packet_size(packet) - + ((const unsigned char *)udp - + (const unsigned char *)dp_packet_l2(packet))); + if (csum_finish(csum)) { + return NULL; + } + tnl->flags |= FLOW_TNL_F_CSUM; + } + tnl->tp_src = udp->udp_src; tnl->tp_dst = udp->udp_dst; @@ -919,13 +931,25 @@ push_udp_header(struct dp_packet *packet, const void *header, int size) /* set udp src port */ udp->udp_src = get_src_port(packet); udp->udp_len = htons(ip_tot_size - sizeof (struct ip_header)); - /* udp_csum is zero */ + + if (udp->udp_csum) { + uint32_t csum = packet_csum_pseudoheader(ip_hdr(dp_packet_data(packet))); + + csum = csum_continue(csum, udp, + ip_tot_size - sizeof (struct ip_header)); + udp->udp_csum = csum_finish(csum); + + if (!udp->udp_csum) { + udp->udp_csum = htons(0xffff); + } + } return udp + 1; } static void * udp_build_header(struct netdev_tunnel_config *tnl_cfg, + const struct flow *tnl_flow, struct ovs_action_push_tnl *data) { struct ip_header *ip; @@ -937,6 +961,13 @@ udp_build_header(struct netdev_tunnel_config *tnl_cfg, udp = (struct udp_header *) (ip + 1); udp->udp_dst = tnl_cfg->dst_port; + if (tnl_flow->tunnel.flags & FLOW_TNL_F_CSUM) { + /* Write a value in now to mark that we should compute the checksum + * later. 0xffff is handy because it is transparent to the + * calculation. */ + udp->udp_csum = htons(0xffff); + } + return udp + 1; } @@ -1183,7 +1214,7 @@ netdev_vxlan_build_header(const struct netdev *netdev, ovs_mutex_lock(&dev->mutex); tnl_cfg = &dev->tnl_cfg; - vxh = udp_build_header(tnl_cfg, data); + vxh = udp_build_header(tnl_cfg, tnl_flow, data); put_16aligned_be32(&vxh->vx_flags, htonl(VXLAN_FLAGS)); put_16aligned_be32(&vxh->vx_vni, htonl(ntohll(tnl_flow->tunnel.tun_id) << 8)); @@ -1288,7 +1319,7 @@ netdev_geneve_build_header(const struct netdev *netdev, ovs_mutex_lock(&dev->mutex); tnl_cfg = &dev->tnl_cfg; - gnh = udp_build_header(tnl_cfg, data); + gnh = udp_build_header(tnl_cfg, tnl_flow, data); gnh->oam = !!(tnl_flow->tunnel.flags & FLOW_TNL_F_OAM); gnh->proto_type = htons(ETH_TYPE_TEB); diff --git a/lib/odp-util.c b/lib/odp-util.c index 4e6a06d1c..7725a09f0 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -516,8 +516,9 @@ format_udp_tnl_push_header(struct ds *ds, const struct ip_header *ip) const struct udp_header *udp; udp = (const struct udp_header *) (ip + 1); - ds_put_format(ds, "udp(src=%"PRIu16",dst=%"PRIu16"),", - ntohs(udp->udp_src), ntohs(udp->udp_dst)); + ds_put_format(ds, "udp(src=%"PRIu16",dst=%"PRIu16",csum=0x%"PRIx16"),", + ntohs(udp->udp_src), ntohs(udp->udp_dst), + ntohs(udp->udp_csum)); return udp + 1; } @@ -854,7 +855,7 @@ ovs_parse_tnl_push(const char *s, struct ovs_action_push_tnl *data) struct ip_header *ip; struct udp_header *udp; struct gre_base_hdr *greh; - uint16_t gre_proto, dl_type, udp_src, udp_dst; + uint16_t gre_proto, dl_type, udp_src, udp_dst, csum; ovs_be32 sip, dip; uint32_t tnl_type = 0, header_len = 0; void *l3, *l4; @@ -899,14 +900,14 @@ ovs_parse_tnl_push(const char *s, struct ovs_action_push_tnl *data) /* Tunnel header */ udp = (struct udp_header *) l4; greh = (struct gre_base_hdr *) l4; - if (ovs_scan_len(s, &n, "udp(src=%"SCNi16",dst=%"SCNi16"),", - &udp_src, &udp_dst)) { + if (ovs_scan_len(s, &n, "udp(src=%"SCNi16",dst=%"SCNi16",csum=0x%"SCNx16"),", + &udp_src, &udp_dst, &csum)) { uint32_t vx_flags, vni; udp->udp_src = htons(udp_src); udp->udp_dst = htons(udp_dst); udp->udp_len = 0; - udp->udp_csum = 0; + udp->udp_csum = htons(csum); if (ovs_scan_len(s, &n, "vxlan(flags=0x%"SCNx32",vni=0x%"SCNx32"))", &vx_flags, &vni)) { @@ -942,8 +943,6 @@ ovs_parse_tnl_push(const char *s, struct ovs_action_push_tnl *data) ovs_16aligned_be32 *options = (ovs_16aligned_be32 *) (greh + 1); if (greh->flags & htons(GRE_CSUM)) { - uint16_t csum; - if (!ovs_scan_len(s, &n, ",csum=0x%"SCNx16, &csum)) { return -EINVAL; } diff --git a/tests/odp.at b/tests/odp.at index 7fda4498a..d615891c4 100644 --- a/tests/odp.at +++ b/tests/odp.at @@ -281,8 +281,9 @@ set(tunnel(tun_id=0xabcdef1234567890,src=1.1.1.1,dst=2.2.2.2,tos=0,ttl=64,tp_src tnl_pop(4) tnl_push(tnl_port(4),header(size=42,type=3,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x40),gre((flags=0x20,proto=0x6558),key=0x1e241)),out_port(1)) tnl_push(tnl_port(4),header(size=46,type=3,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x40),gre((flags=0xa0,proto=0x6558),csum=0x0,key=0x1e241)),out_port(1)) -tnl_push(tnl_port(6),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=4789),vxlan(flags=0x8000000,vni=0x1c7)),out_port(1)) -tnl_push(tnl_port(6),header(size=50,type=5,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=6081),geneve(oam,vni=0x1c7)),out_port(1)) +tnl_push(tnl_port(6),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0x8000000,vni=0x1c7)),out_port(1)) +tnl_push(tnl_port(6),header(size=50,type=5,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=6081,csum=0x0),geneve(oam,vni=0x1c7)),out_port(1)) +tnl_push(tnl_port(6),header(size=50,type=5,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=6081,csum=0xffff),geneve(vni=0x1c7)),out_port(1)) ]) AT_CHECK_UNQUOTED([ovstest test-odp parse-actions < actions.txt], [0], [`cat actions.txt` diff --git a/tests/tunnel-push-pop.at b/tests/tunnel-push-pop.at index 77dde69dd..72216efb2 100644 --- a/tests/tunnel-push-pop.at +++ b/tests/tunnel-push-pop.at @@ -9,7 +9,7 @@ AT_CHECK([ovs-vsctl add-port int-br t2 -- set Interface t2 type=vxlan \ -- add-port int-br t1 -- set Interface t1 type=gre \ options:remote_ip=1.1.2.92 options:key=456 ofport_request=3\ -- add-port int-br t3 -- set Interface t3 type=vxlan \ - options:remote_ip=1.1.2.93 options:out_key=flow ofport_request=4\ + options:remote_ip=1.1.2.93 options:out_key=flow options:csum=true ofport_request=4\ -- add-port int-br t4 -- set Interface t4 type=geneve \ options:remote_ip=1.1.2.92 options:key=123 ofport_request=5\ ], [0]) @@ -23,7 +23,7 @@ dummy@ovs-dummy: hit:0 missed:0 int-br 65534/2: (dummy) t1 3/3: (gre: key=456, remote_ip=1.1.2.92) t2 2/4789: (vxlan: key=123, remote_ip=1.1.2.92) - t3 4/4789: (vxlan: out_key=flow, remote_ip=1.1.2.93) + t3 4/4789: (vxlan: csum=true, out_key=flow, remote_ip=1.1.2.93) t4 5/6081: (geneve: key=123, remote_ip=1.1.2.92) ]) @@ -67,14 +67,14 @@ dnl Check VXLAN tunnel push AT_CHECK([ovs-ofctl add-flow int-br action=2]) AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout]) AT_CHECK([tail -1 stdout], [0], - [Datapath actions: tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=4789),vxlan(flags=0x8000000,vni=0x7b)),out_port(100)) + [Datapath actions: tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0x8000000,vni=0x7b)),out_port(100)) ]) -dnl Check VXLAN tunnel push set tunnel id by flow +dnl Check VXLAN tunnel push set tunnel id by flow and checksum AT_CHECK([ovs-ofctl add-flow int-br "actions=set_tunnel:124,4"]) AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout]) AT_CHECK([tail -1 stdout], [0], - [Datapath actions: tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b7,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.93,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=4789),vxlan(flags=0x8000000,vni=0x7c)),out_port(100)) + [Datapath actions: tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b7,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.93,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=4789,csum=0xffff),vxlan(flags=0x8000000,vni=0x7c)),out_port(100)) ]) dnl Check GRE tunnel push -- cgit v1.2.1 From 8fc55661c57b26ab84a2baa5ef235f1a79c20633 Mon Sep 17 00:00:00 2001 From: Jesse Gross Date: Tue, 7 Apr 2015 17:57:36 -0700 Subject: packet: Avoid array of struct with zero length member. Windows doesn't like that the Geneve header has an array of options with each have a zero length member (the variable data). Nothing is accessing the data now, so just replace the member with a comment - we can use pointer arithmetic when necessary. Reported-by: Gurucharan Shetty Signed-off-by: Jesse Gross --- lib/packets.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/packets.h b/lib/packets.h index 29ea54f0f..b146a5069 100644 --- a/lib/packets.h +++ b/lib/packets.h @@ -730,7 +730,7 @@ struct geneve_opt { uint8_t r2:1; uint8_t r1:1; #endif - uint8_t opt_data[]; + /* Option data */ }; struct genevehdr { -- cgit v1.2.1 From 46e7137c77d845c488e17b718eac7c3fb97cedcc Mon Sep 17 00:00:00 2001 From: Jesse Gross Date: Tue, 7 Apr 2015 18:55:54 -0700 Subject: geneve: Zero header before parsing userspace tunneling action. When we parse the text representation of the Geneve action the header is not fully initialized. Besides the obvious potential to generate an action that the user did not actually specify, this also causes intermittent unit test failures when an action is read in and printed out and the result is different. Signed-off-by: Jesse Gross --- lib/odp-util.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/odp-util.c b/lib/odp-util.c index 7725a09f0..8a81f6b47 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -921,6 +921,7 @@ ovs_parse_tnl_push(const char *s, struct ovs_action_push_tnl *data) } else if (ovs_scan_len(s, &n, "geneve(")) { struct genevehdr *gnh = (struct genevehdr *) (udp + 1); + memset(gnh, 0, sizeof *gnh); if (ovs_scan_len(s, &n, "oam,")) { gnh->oam = 1; } -- cgit v1.2.1 From dcd032186066c5899c8b14394fa91fed26a501d7 Mon Sep 17 00:00:00 2001 From: Flavio Leitner Date: Wed, 8 Apr 2015 13:35:54 -0300 Subject: testsuite: work around patch bug Due to a CVE bug, the patch was modified to not allow following symlinks out of the workdir. However, this causes a bug when there is a regular file out of the workdir which breaks the current testsuite build. Steps to reproduce: ./boot.sh mkdir _gcc && cd _gcc ../configure make [...] /bin/sh /home/fleitner/ovs/testsuite/build-aux/missing autom4te --language=autotest -I '..' -o ../tests/testsuite.tmp ../tests/testsuite.at patch -p0 ../tests/testsuite.tmp ../tests/testsuite.patch Invalid file name ../tests/testsuite.tmp -- skipping patch Makefile:5155: recipe for target '../tests/testsuite' failed make[2]: *** [../tests/testsuite] Error 1 make[2]: Leaving directory '/home/fleitner/NetworkingServices/openvswitch/repo/testsuite/_gcc' Makefile:4087: recipe for target 'all-recursive' failed make[1]: *** [all-recursive] Error 1 Since it's just a temporary file, this patch changes to use the workdir as the place to put the file. Signed-off-by: Flavio Leitner Signed-off-by: Gurucharan Shetty --- tests/automake.mk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/automake.mk b/tests/automake.mk index c691cf907..fdc3118c6 100644 --- a/tests/automake.mk +++ b/tests/automake.mk @@ -200,9 +200,9 @@ clean-local: AUTOTEST = $(AUTOM4TE) --language=autotest $(TESTSUITE): package.m4 $(TESTSUITE_AT) $(COMMON_MACROS_AT) $(TESTSUITE_PATCH) - $(AM_V_GEN)$(AUTOTEST) -I '$(srcdir)' -o $@.tmp $@.at - patch -p0 $@.tmp $(TESTSUITE_PATCH) - $(AM_V_at)mv $@.tmp $@ + $(AM_V_GEN)$(AUTOTEST) -I '$(srcdir)' -o testsuite.tmp $@.at + patch -p0 testsuite.tmp $(TESTSUITE_PATCH) + $(AM_V_at)mv testsuite.tmp $@ $(KMOD_TESTSUITE): package.m4 $(KMOD_TESTSUITE_AT) $(COMMON_MACROS_AT) $(AM_V_GEN)$(AUTOTEST) -I '$(srcdir)' -o $@.tmp $@.at -- cgit v1.2.1 From 0a46bca787884c914c045ac3838595cbf19e172c Mon Sep 17 00:00:00 2001 From: Nithin Raju Date: Wed, 8 Apr 2015 16:41:36 -0700 Subject: INSTALL.Windows: update documentation The documentation to run the executables has fallen behind quite a bit. In this patch, we make a few updates. There's more to come. The patch assumes the user has not run 'make install' or does not have access to an installer. Signed-off-by: Nithin Raju Signed-off-by: Gurucharan Shetty --- INSTALL.Windows.md | 356 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 239 insertions(+), 117 deletions(-) diff --git a/INSTALL.Windows.md b/INSTALL.Windows.md index e84013aab..cd6ba4012 100644 --- a/INSTALL.Windows.md +++ b/INSTALL.Windows.md @@ -136,128 +136,251 @@ Steps to install the module --------------------------- 01> Run ./uninstall.cmd to remove the old extension. -02> Run ./install.cmd to insert the new one. For this to work you will have to + +02> Run ./install.cmd to insert the new one. For this to work you will have to turn on TESTSIGNING boot option or 'Disable Driver Signature Enforcement' during boot. -03> In the Virtual Switch Manager configuration you should now see "VMWare OVS -Extension" under 'Virtual Switch Extensions'. Click the check box to enable the -extension. - -Steps to run the user processes & configure VXLAN ports -------------------------------------------------------- - -01> Create the conf db file. -ovsdb\ovsdb-tool.exe create conf.db .\vswitchd\vswitch.ovsschema - -02> Run ovsdb-server -ovsdb\ovsdb-server.exe -v --remote=ptcp:6640:127.0.0.1 conf.db - -03> Create integration bridge & pif bridge -utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 add-br br-int -utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 add-br br-pif - -04> Dump the ports -utilities\ovs-dpctl.exe show - -* Sample output shows up like this. Currently it is not possible to figure out -* the mapping between VIF and VM from the output. - -$ utilities\ovs-dpctl.exe show -2014-06-27T01:55:32Z|00001|socket_util|ERR|4789:0.0.0.0: -socket: Either the application has not called WSAStartup, or WSAStartup failed. - <<< Ignore this error, it is harmless. -system@ovs-system: - lookups: hit:0 missed:0 lost:0 - flows: 0 - masks: hit:0 total:0 hit/pkt:0.00 - port 16777216: internal <<< VTEP created by AllowManagementOS - setting - port 16777225: external.1 <<< Physical NIC - port 16777288: vmNICEmu.1000048 <<< VIF #1 - port 16777289: vmNICSyn.1000049 <<< VIF #2 - - -05> Add the physical NIC and the internal port to br-pif -utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 add-port br-pif - -Eg: -utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 add-port br-pif external.1 -utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 add-port br-pif internal - -06> Add the VIFs to br-int -utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 add-port br-int - -Eg: -utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 add-port br-int vmNICEmu.1000048 -utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 add-port br-int vmNICSyn.1000049 - -07> Verify the status -utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 show - -Eg: -$ utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 show -4cd86499-74df-48bd-a64d-8d115b12a9f2 - Bridge br-pif - Port internal - Interface internal - Port "external.1" - Interface "external.1" - Port br-pif - Interface br-pif - type: internal - Bridge br-int - Port br-int - Interface br-int - type: internal - Port "vmNICEmu.1000048" - Interface "vmNICEmu.1000048" - Port "vmNICSyn.1000049" - Interface "vmNICSyn.1000049" - - -09> Run vswitchd -vswitchd\ovs-vswitchd.exe -v tcp:127.0.0.1:6640 - -10> You can figure out the port name to MAC address mapping now. (optional) -utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 list interface - -//********** VXLAN PORT CONFIGURATION (Supports Multiple ports) ************// -(Remove all patch ports added to create VLAN networks.) -11> Add the vxlan port between 172.168.201.101 <-> 172.168.201.102 -utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 add-port br-int vxlan-1 -utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 set Interface vxlan-1 type=vxlan -utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 set Interface vxlan-1 options:local_ip=172.168.201.101 -utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 set Interface vxlan-1 options:remote_ip=172.168.201.102 -utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 set Interface vxlan-1 options:in_key=flow -utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 set Interface vxlan-1 options:out_key=flow - -12> Add the vxlan port between 172.168.201.101 <-> 172.168.201.105 -utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 add-port br-int vxlan-2 -utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 set Interface vxlan-2 type=vxlan -utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 set Interface vxlan-2 options:local_ip=172.168.201.102 -utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 set Interface vxlan-2 options:remote_ip=172.168.201.105 -utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 set Interface vxlan-2 options:in_key=flow -utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 set Interface vxlan-2 options:out_key=flow - - -//********** VLAN CONFIGURATION (Using patch ports) ************// -(Remove all VXLAN ports from the configuration.) -13> Add a patch port from br-int to br-pif -utilities/ovs-vsctl.exe -- add-port br-int patch-to-pif -utilities/ovs-vsctl.exe -- set interface patch-to-pif type=patch options:peer=patch-to-int - -14> Add a patch port from br-pif to br-int -utilities/ovs-vsctl.exe -- add-port br-pif patch-to-int -utilities/ovs-vsctl.exe -- set interface patch-to-int type=patch options:peer=patch-to-pif - -15> Re-Add the VIF ports with the VLAN tag -utilities\ovs-vsctl.exe add-port br-int vmNICEmu.1000048 tag=900 -utilities\ovs-vsctl.exe add-port br-int vmNICSyn.1000049 tag=900 + +03> In the Virtual Switch Manager configuration you can enable the Open vSwitch +Extension on an existing switch or create a new switch. If you are using an +existing switch, make sure to enable the "Allow Management OS" option for VXLAN +to work (covered later). + +The command to create a new switch named 'OVS-Extended-Switch' using a physical +NIC named 'Ethernet 1' is: + % New-VMSwitch "OVS-Extended-Switch" -AllowManagementOS $true \ + -NetAdapterName "Ethernet 1" + +Note: you can obtain the list of physical NICs on the host using +'Get-NetAdapter' command. + +04> In the properties of any switch, you should should now see "Open +vSwitch Extension" under 'Extensions'. Click the check box to enable the +extension. An alternative way to do the same is to run the following command: + % Enable-VMSwitchExtension "Open vSwitch Extension" OVS-Extended-Switch + +Note: If you enabled the extension using the command line, a delay of a few +seconds has been observed for the change to be reflected in the UI. This is +not a bug in Open vSwitch. + +Steps to run the user processes & configure ports +------------------------------------------------- +NOTE: The userspace executables built in Open vSwitch for Hyper-V links +statically with the pthread library mentioned above. However, the pthread +library has been found to have a dependency on a DLL file called +"pthreadVC2.dll" which is part of the pthread package and typically resides in +"C:\pthread\dll\x86". In order to resolve the dependency, add the location of +the DLL file to Windows environment variable %Path%. An alternative is to copy +the DLL file into each of the directories where the OVS executables are +located. Without having this DLL dependency resolved, the OVS executables will +not run. They exit without showing any error/output. + +01> Create the OVSDB file + % ovsdb\ovsdb-tool.exe create conf.db .\vswitchd\vswitch.ovsschema + +02> Start ovsdb-server [IN A NEW CONSOLE] + % ovsdb\ovsdb-server.exe -v --remote=punix:db.sock conf.db + +03> Start ovs-vswitchd [IN A NEW CONSOLE] + % vswitchd\ovs-vswitchd.exe -v + +04> Create integration bridge & pif bridge + % utilities\ovs-vsctl.exe add-br br-int + % utilities\ovs-vsctl.exe add-br br-pif + +NOTE: There's a known bug that running the ovs-vsctl.exe command does not +terminate. This is generally solved by having ovs-vswitchd.exe running. If +you face the issue despite that, hit Ctrl-C to terminate ovs-vsctl.exe and +check the output to see if your command succeeded. + +NOTE: There's a known bug that the ports added to OVSDB via ovs-vsctl.exe don't +get to the kernel datapath immediately, ie. they don't whow up in the output of +"ovs-dpctl.exe show" even though they show up in output of "ovs-vsctl.exe +show". In order to workaround this issue, restart ovs-vswitchd.exe. + +05> Dump the ports in the kernel datapath +.\ % utilities\ovs-dpctl.exe show + +* Sample output is as follows: + + % utilities\ovs-dpctl.exe show + system@ovs-system: + lookups: hit:0 missed:0 lost:0 + flows: 0 + port 2: br-pif (internal) <<< internal port on 'br-pif' bridge + port 1: br-int (internal) <<< internal port on 'br-int' bridge + +06> Dump the ports in the OVSDB + % utilities\ovs-vsctl.exe show + +* Sample output is as follows: + % .\ovs-vsctl.exe show + a56ec7b5-5b1f-49ec-a795-79f6eb63228b + Bridge br-pif + Port br-pif + Interface br-pif + type: internal + Bridge br-int + Port br-int + Interface br-int + type: internal + +07> Add the physical NIC and the internal port to br-pif. + +In OVS for Hyper-V, we use 'external' as a special name to refer to the +physical NICs connected to the Hyper-V switch. An index is added to this +special name to refer to the particular physical NIC. Eg. 'external.1' refers +to the first physical NIC on the Hyper-V switch. + +Note: Currently, we assume that the Hyper-V switch on which OVS extension is +enabled has a single physical NIC connected to it. + +Interal port is the virtual adapter created on the Hyper-V switch using the +'AllowManagementOS' setting. This has already been setup while creating the +switch using the instructions above. In OVS for Hyper-V, we use a 'internal' +as a special name to refer to that adapter. + + % utilities\ovs-vsctl.exe add-port br-pif external.1 + % utilities\ovs-vsctl.exe add-port br-pif internal + +* Dumping the ports should show the additional ports that were just added. + Sample output shows up as follows: + + % utilities\ovs-dpctl.exe show + system@ovs-system: + lookups: hit:0 missed:0 lost:0 + flows: 0 + port 4: internal (internal) <<< 'AllowManagementOS' adapter on + Hyper-V switch + port 2: br-pif (internal) + port 1: br-int (internal + port 3: external.1 <<< Physical NIC + + % .\ovs-vsctl.exe show + a56ec7b5-5b1f-49ec-a795-79f6eb63228b + Bridge br-pif + Port internal + Interface internal + Port br-pif + Interface br-pif + type: internal + Bridge br-int + Port "external.1" + Interface "external.1" + Port br-int + Interface br-int + type: internal + +08> Add the VIFs to br-int + +Adding VIFs to openvswitch is a two step procedure. The first step is to +assign a 'OVS port name' which is a unique name across all VIFs on this +Hyper-V. The next step is to add the VIF to the ovsdb using its 'OVS port +name' as key. + +08a> Assign a unique 'OVS port name' to the VIF + +Note that the VIF needs to have been disconnected from the Hyper-V switch +before assigning a 'OVS port name' to it. In the example below, we assign a +'OVS port name' called 'ovs-port-a' to a VIF on a VM by name 'VM1'. By using +index 0 for '$vnic', the first VIF of the VM is being addressed. After +assigning the name 'ovs-port-a', the VIF is connected back to the Hyper-V +switch with name 'OVS-HV-Switch', which is assumed to be the Hyper-V switch +with OVS extension enabled. + + Eg: + % import-module .\datapath-windows\misc\OVS.psm1 + % $vnic = Get-VMNetworkAdapter + % Disconnect-VMNetworkAdapter -VMNetworkAdapter $vnic[0] + % $vnic[0] | Set-VMNetworkAdapterOVSPort -OVSPortName ovs-port-a + % Connect-VMNetworkAdapter -VMNetworkAdapter $vnic[0] \ + -SwitchName OVS-Extended-Switch + +08b> Add the VIFs to br-int in ovsdb + + Eg: + % utilities\ovs-vsctl.exe add-port br-int ovs-port-a + +09> Verify the status + % utilities\ovs-dpctl.exe show + system@ovs-system: + lookups: hit:0 missed:0 lost:0 + flows: 0 + port 4: internal (internal) + port 5: ovs-port-a + port 2: br-pif (internal) + port 1: br-int (internal + port 3: external.1 + + % utilities\ovs-vsctl.exe show + 4cd86499-74df-48bd-a64d-8d115b12a9f2 + Bridge br-pif + Port internal + Interface internal + Port "external.1" + Interface "external.1" + Port br-pif + Interface br-pif + type: internal + Bridge br-int + Port br-int + Interface br-int + type: internal + Port "ovs-port-a" + Interface "ovs-port-a" + +Steps to configure patch ports and switch VLAN tagging +------------------------------------------------------ +The Windows Open vSwitch implementation support VLAN tagging in the switch. +Switch VLAN tagging along with patch ports between 'br-int' and 'br-pif' is +used to configure VLAN tagging functionality between two VMs on different +Hyper-Vs. The following examples demonstrate how it can be done: + +01> Add a patch port from br-int to br-pif + % utilities/ovs-vsctl.exe -- add-port br-int patch-to-pif + % utilities/ovs-vsctl.exe -- set interface patch-to-pif type=patch \ + options:peer=patch-to-int + +02> Add a patch port from br-pif to br-int + % utilities/ovs-vsctl.exe -- add-port br-pif patch-to-int + % utilities/ovs-vsctl.exe -- set interface patch-to-int type=patch \ + options:peer=patch-to-pif + +03> Re-Add the VIF ports with the VLAN tag + % utilities\ovs-vsctl.exe add-port br-int ovs-port-a tag=900 + % utilities\ovs-vsctl.exe add-port br-int ovs-port-b tag=900 + +Steps to add VXLAN tunnels +-------------------------- +The Windows Open vSwitch implementation support VXLAN tunnels. To add VXLAN +tunnels, the following steps serve as examples. + +Note that, any patch ports created between br-int and br-pif MUST be beleted +prior to adding VXLAN tunnels. + +01> Add the vxlan port between 172.168.201.101 <-> 172.168.201.102 + % utilities\ovs-vsctl.exe add-port br-int vxlan-1 + % utilities\ovs-vsctl.exe set Interface vxlan-1 type=vxlan + % utilities\ovs-vsctl.exe set Interface vxlan-1 \ + options:local_ip=172.168.201.101 + % utilities\ovs-vsctl.exe set Interface vxlan-1 \ + options:remote_ip=172.168.201.102 + % utilities\ovs-vsctl.exe set Interface vxlan-1 options:in_key=flow + % utilities\ovs-vsctl.exe set Interface vxlan-1 options:out_key=flow + +02> Add the vxlan port between 172.168.201.101 <-> 172.168.201.105 + % utilities\ovs-vsctl.exe add-port br-int vxlan-2 + % utilities\ovs-vsctl.exe set Interface vxlan-2 type=vxlan + % utilities\ovs-vsctl.exe set Interface vxlan-2 \ + options:local_ip=172.168.201.102 + % utilities\ovs-vsctl.exe set Interface vxlan-2 \ + options:remote_ip=172.168.201.105 + % utilities\ovs-vsctl.exe set Interface vxlan-2 options:in_key=flow + % utilities\ovs-vsctl.exe set Interface vxlan-2 options:out_key=flow Requirements ------------ - * We require that you don't disable the "Allow management operating system to share this network adapter" under 'Virtual Switch Properties' > 'Connection type: External network', in the HyperV virtual network switch configuration. @@ -269,7 +392,6 @@ disabling TX/RX offloads for both the VM's as well as the HyperV. Windows autobuild service ------------------------- - AppVeyor (appveyor.com) provides a free Windows autobuild service for opensource projects. Open vSwitch has integration with AppVeyor for continuous build. A developer can build test his changes for Windows by -- cgit v1.2.1 From 5f5ebd4cc8bfede3410fbb5db574693eae8c29e0 Mon Sep 17 00:00:00 2001 From: Flavio Leitner Date: Wed, 8 Apr 2015 14:30:40 -0300 Subject: testsuite: ofproto-dpif: fix test names Some tests were not included when running the make TESTSUITEFLAGS="-k ofproto-dpif" check because the test name was out of the expected pattern. Signed-off-by: Flavio Leitner Acked-by: Joe Stringer --- tests/ofproto-dpif.at | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at index 89ba11222..139dfdd6b 100644 --- a/tests/ofproto-dpif.at +++ b/tests/ofproto-dpif.at @@ -6,7 +6,7 @@ AT_CHECK([ovs-appctl revalidator/wait]) OVS_VSWITCHD_STOP AT_CLEANUP -AT_SETUP([ofproto-dpif, active-backup bonding]) +AT_SETUP([ofproto-dpif - active-backup bonding]) # Create br0 with interfaces p1, p2 and p7, creating bond0 with p1 and p2 # and br1 with interfaces p3, p4 and p8. # toggle p1,p2 of bond0 up and down to test bonding in active-backup mode. @@ -53,7 +53,7 @@ recirc_id=0,rarp,in_port=4,vlan_tci=0x0000/0x1fff,dl_src=50:54:00:00:00:0b,dl_ds OVS_VSWITCHD_STOP AT_CLEANUP -AT_SETUP([ofproto-dpif, balance-slb bonding]) +AT_SETUP([ofproto-dpif - balance-slb bonding]) # Create br0 with interfaces bond0(p1, p2, p3) and p7, # and br1 with interfaces p4, p5, p6 and p8. # p1 <-> p4, p2 <-> p5, p3 <-> p6 @@ -96,7 +96,7 @@ AT_CHECK([test `egrep 'in_port\(6\)' br1_flows.txt |wc -l` -gt 3]) OVS_VSWITCHD_STOP AT_CLEANUP -AT_SETUP([ofproto-dpif, balance-tcp bonding]) +AT_SETUP([ofproto-dpif - balance-tcp bonding]) # Create br0 with interfaces bond0(p1, p2, p3) and p7, # and br1 with interfaces bond1(p4, p5, p6) and p8. # bond0 <-> bond1 @@ -149,7 +149,7 @@ OVS_VSWITCHD_STOP() AT_CLEANUP # Makes sure recirculation does not change the way packet is handled. -AT_SETUP([ofproto-dpif, balance-tcp bonding, different recirc flow ]) +AT_SETUP([ofproto-dpif - balance-tcp bonding, different recirc flow ]) OVS_VSWITCHD_START( [add-bond br0 bond0 p1 p2 bond_mode=balance-tcp lacp=active \ other-config:lacp-time=fast other-config:bond-rebalance-interval=0 -- \ @@ -5214,7 +5214,7 @@ AT_CHECK([STRIP_XIDS stdout | sed -n 's/duration=[[0-9]]*\.[[0-9]]*s/duration=0. OVS_VSWITCHD_STOP AT_CLEANUP -AT_SETUP([idle_age and hard_age increase over time]) +AT_SETUP([ofproto-dpif - idle_age and hard_age increase over time]) OVS_VSWITCHD_START # get_ages DURATION HARD IDLE -- cgit v1.2.1 From d0d808fda035e86602f6e2b4ba414494055e4579 Mon Sep 17 00:00:00 2001 From: Gurucharan Shetty Date: Thu, 9 Apr 2015 08:00:13 -0700 Subject: INSTALL.Windows: Add details about local build and installation. This commits adds the following. * Clearly callout to set pthread-win32's dll path in $PATH * Details about running parallel make and parallel unit tests. * Installing Open vSwitch locally via 'make install' * Update the steps to run the user processes by relying on the previous 'make install'. The steps now run the daemons in the background with the creation of a logfile and pidfile. Signed-off-by: Gurucharan Shetty Acked-by: Nithin Raju --- INSTALL.Windows.md | 144 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 85 insertions(+), 59 deletions(-) diff --git a/INSTALL.Windows.md b/INSTALL.Windows.md index cd6ba4012..03737a76c 100644 --- a/INSTALL.Windows.md +++ b/INSTALL.Windows.md @@ -46,7 +46,8 @@ Visual studio's linker is used. You should also see a 'which sort' report * For pthread support, install the library, dll and includes of pthreads-win32 project from ftp://sourceware.org/pub/pthreads-win32/prebuilt-dll-2-9-1-release to a -directory (e.g.: C:/pthread). +directory (e.g.: C:/pthread). You should add the pthread-win32's dll +path (e.g.: C:\pthread\dll\x86) to the Windows' PATH environment variable. * Get the Open vSwitch sources from either cloning the repo using git or from a distribution tar ball. @@ -73,10 +74,32 @@ or from a distribution tar ball. % make -* To run all the unit tests: + For faster compilation, you can pass the '-j' argument to make. For + example, to run 4 jobs simultaneously, run 'make -j4'. + + Note: MSYS 1.0.18 has a bug that causes parallel make to hang. You + can overcome this by downgrading to MSYS 1.0.17. A simple way to + downgrade is to exit all MinGW sessions and then run the command + 'mingw-get upgrade msys-core-bin=1.0.17-1' from MSVC developers command + prompt. + +* To run all the unit tests in Open vSwitch, one at a time: % make check + To run all the unit tests in Open vSwitch, up to 8 in parallel: + + % make check TESTSUITEFLAGS="-j8" + +* To install all the compiled executables on the local machine, run: + + % make install + + The above command will install the Open vSwitch executables in + C:/openvswitch. You can add 'C:\openvswitch\usr\bin' and + 'C:\openvswitch\usr\sbin' to Windows' PATH environment variable + for easy access. + OpenSSL, Open vSwitch and Visual C++ ------------------------------------ To get SSL support for Open vSwitch on Windows, do the following: @@ -165,45 +188,52 @@ not a bug in Open vSwitch. Steps to run the user processes & configure ports ------------------------------------------------- -NOTE: The userspace executables built in Open vSwitch for Hyper-V links -statically with the pthread library mentioned above. However, the pthread -library has been found to have a dependency on a DLL file called -"pthreadVC2.dll" which is part of the pthread package and typically resides in -"C:\pthread\dll\x86". In order to resolve the dependency, add the location of -the DLL file to Windows environment variable %Path%. An alternative is to copy -the DLL file into each of the directories where the OVS executables are -located. Without having this DLL dependency resolved, the OVS executables will -not run. They exit without showing any error/output. +The following steps assume that you have installed the Open vSwitch +utilities in the local machine via 'make install'. + +01> Create the database. + % ovsdb-tool create C:\openvswitch\etc\openvswitch\conf.db \ + C:\openvswitch\usr\share\openvswitch\vswitch.ovsschema + +02> Start the ovsdb-server and initialize the database. + % ovsdb-server -vfile:info --remote=punix:db.sock --log-file --pidfile \ + --detach + % ovs-vsctl --no-wait init + + If you would like to terminate the started ovsdb-server, run: + % ovs-appctl -t ovsdb-server exit + + (Note that the logfile is created at C:/openvswitch/var/log/openvswitch/) -01> Create the OVSDB file - % ovsdb\ovsdb-tool.exe create conf.db .\vswitchd\vswitch.ovsschema +03> Start ovs-vswitchd. + % ovs-vswitchd -vfile:info --log-file --pidfile --detach -02> Start ovsdb-server [IN A NEW CONSOLE] - % ovsdb\ovsdb-server.exe -v --remote=punix:db.sock conf.db + If you would like to terminate the started ovs-vswitchd, run: + % ovs-appctl exit -03> Start ovs-vswitchd [IN A NEW CONSOLE] - % vswitchd\ovs-vswitchd.exe -v + (Note that the logfile is created at C:/openvswitch/var/log/openvswitch/) 04> Create integration bridge & pif bridge - % utilities\ovs-vsctl.exe add-br br-int - % utilities\ovs-vsctl.exe add-br br-pif + % ovs-vsctl add-br br-int + % ovs-vsctl add-br br-pif -NOTE: There's a known bug that running the ovs-vsctl.exe command does not -terminate. This is generally solved by having ovs-vswitchd.exe running. If -you face the issue despite that, hit Ctrl-C to terminate ovs-vsctl.exe and +NOTE: There's a known bug that running the ovs-vsctl command does not +terminate. This is generally solved by having ovs-vswitchd running. If +you face the issue despite that, hit Ctrl-C to terminate ovs-vsctl and check the output to see if your command succeeded. -NOTE: There's a known bug that the ports added to OVSDB via ovs-vsctl.exe don't -get to the kernel datapath immediately, ie. they don't whow up in the output of -"ovs-dpctl.exe show" even though they show up in output of "ovs-vsctl.exe -show". In order to workaround this issue, restart ovs-vswitchd.exe. +NOTE: There's a known bug that the ports added to OVSDB via ovs-vsctl don't +get to the kernel datapath immediately, ie. they don't show up in the output of +"ovs-dpctl show" even though they show up in output of "ovs-vsctl show". +In order to workaround this issue, restart ovs-vswitchd. (You can terminate +ovs-vswitchd by running 'ovs-appctl exit'.) 05> Dump the ports in the kernel datapath -.\ % utilities\ovs-dpctl.exe show + % ovs-dpctl show * Sample output is as follows: - % utilities\ovs-dpctl.exe show + % ovs-dpctl show system@ovs-system: lookups: hit:0 missed:0 lost:0 flows: 0 @@ -211,10 +241,10 @@ show". In order to workaround this issue, restart ovs-vswitchd.exe. port 1: br-int (internal) <<< internal port on 'br-int' bridge 06> Dump the ports in the OVSDB - % utilities\ovs-vsctl.exe show + % ovs-vsctl show * Sample output is as follows: - % .\ovs-vsctl.exe show + % ovs-vsctl show a56ec7b5-5b1f-49ec-a795-79f6eb63228b Bridge br-pif Port br-pif @@ -240,13 +270,13 @@ Interal port is the virtual adapter created on the Hyper-V switch using the switch using the instructions above. In OVS for Hyper-V, we use a 'internal' as a special name to refer to that adapter. - % utilities\ovs-vsctl.exe add-port br-pif external.1 - % utilities\ovs-vsctl.exe add-port br-pif internal + % ovs-vsctl add-port br-pif external.1 + % ovs-vsctl add-port br-pif internal * Dumping the ports should show the additional ports that were just added. Sample output shows up as follows: - % utilities\ovs-dpctl.exe show + % ovs-dpctl show system@ovs-system: lookups: hit:0 missed:0 lost:0 flows: 0 @@ -256,7 +286,7 @@ as a special name to refer to that adapter. port 1: br-int (internal port 3: external.1 <<< Physical NIC - % .\ovs-vsctl.exe show + % ovs-vsctl show a56ec7b5-5b1f-49ec-a795-79f6eb63228b Bridge br-pif Port internal @@ -299,10 +329,10 @@ with OVS extension enabled. 08b> Add the VIFs to br-int in ovsdb Eg: - % utilities\ovs-vsctl.exe add-port br-int ovs-port-a + % ovs-vsctl add-port br-int ovs-port-a 09> Verify the status - % utilities\ovs-dpctl.exe show + % ovs-dpctl show system@ovs-system: lookups: hit:0 missed:0 lost:0 flows: 0 @@ -312,7 +342,7 @@ with OVS extension enabled. port 1: br-int (internal port 3: external.1 - % utilities\ovs-vsctl.exe show + % ovs-vsctl show 4cd86499-74df-48bd-a64d-8d115b12a9f2 Bridge br-pif Port internal @@ -337,18 +367,18 @@ used to configure VLAN tagging functionality between two VMs on different Hyper-Vs. The following examples demonstrate how it can be done: 01> Add a patch port from br-int to br-pif - % utilities/ovs-vsctl.exe -- add-port br-int patch-to-pif - % utilities/ovs-vsctl.exe -- set interface patch-to-pif type=patch \ + % ovs-vsctl add-port br-int patch-to-pif + % ovs-vsctl set interface patch-to-pif type=patch \ options:peer=patch-to-int 02> Add a patch port from br-pif to br-int - % utilities/ovs-vsctl.exe -- add-port br-pif patch-to-int - % utilities/ovs-vsctl.exe -- set interface patch-to-int type=patch \ + % ovs-vsctl add-port br-pif patch-to-int + % ovs-vsctl set interface patch-to-int type=patch \ options:peer=patch-to-pif 03> Re-Add the VIF ports with the VLAN tag - % utilities\ovs-vsctl.exe add-port br-int ovs-port-a tag=900 - % utilities\ovs-vsctl.exe add-port br-int ovs-port-b tag=900 + % ovs-vsctl add-port br-int ovs-port-a tag=900 + % ovs-vsctl add-port br-int ovs-port-b tag=900 Steps to add VXLAN tunnels -------------------------- @@ -359,24 +389,20 @@ Note that, any patch ports created between br-int and br-pif MUST be beleted prior to adding VXLAN tunnels. 01> Add the vxlan port between 172.168.201.101 <-> 172.168.201.102 - % utilities\ovs-vsctl.exe add-port br-int vxlan-1 - % utilities\ovs-vsctl.exe set Interface vxlan-1 type=vxlan - % utilities\ovs-vsctl.exe set Interface vxlan-1 \ - options:local_ip=172.168.201.101 - % utilities\ovs-vsctl.exe set Interface vxlan-1 \ - options:remote_ip=172.168.201.102 - % utilities\ovs-vsctl.exe set Interface vxlan-1 options:in_key=flow - % utilities\ovs-vsctl.exe set Interface vxlan-1 options:out_key=flow + % ovs-vsctl add-port br-int vxlan-1 + % ovs-vsctl set Interface vxlan-1 type=vxlan + % ovs-vsctl set Interface vxlan-1 options:local_ip=172.168.201.101 + % ovs-vsctl set Interface vxlan-1 options:remote_ip=172.168.201.102 + % ovs-vsctl set Interface vxlan-1 options:in_key=flow + % ovs-vsctl set Interface vxlan-1 options:out_key=flow 02> Add the vxlan port between 172.168.201.101 <-> 172.168.201.105 - % utilities\ovs-vsctl.exe add-port br-int vxlan-2 - % utilities\ovs-vsctl.exe set Interface vxlan-2 type=vxlan - % utilities\ovs-vsctl.exe set Interface vxlan-2 \ - options:local_ip=172.168.201.102 - % utilities\ovs-vsctl.exe set Interface vxlan-2 \ - options:remote_ip=172.168.201.105 - % utilities\ovs-vsctl.exe set Interface vxlan-2 options:in_key=flow - % utilities\ovs-vsctl.exe set Interface vxlan-2 options:out_key=flow + % ovs-vsctl add-port br-int vxlan-2 + % ovs-vsctl set Interface vxlan-2 type=vxlan + % ovs-vsctl set Interface vxlan-2 options:local_ip=172.168.201.102 + % ovs-vsctl set Interface vxlan-2 options:remote_ip=172.168.201.105 + % ovs-vsctl set Interface vxlan-2 options:in_key=flow + % ovs-vsctl set Interface vxlan-2 options:out_key=flow Requirements -- cgit v1.2.1 From 0be55e389d2f12dbbf5dca5c16a7b2c8177e58ff Mon Sep 17 00:00:00 2001 From: Gurucharan Shetty Date: Thu, 9 Apr 2015 08:54:23 -0700 Subject: INSTALL.Windows: Add documentation about Windows services. Signed-off-by: Gurucharan Shetty Acked-by: Nithin Raju --- INSTALL.Windows.md | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/INSTALL.Windows.md b/INSTALL.Windows.md index 03737a76c..00db4a374 100644 --- a/INSTALL.Windows.md +++ b/INSTALL.Windows.md @@ -416,6 +416,57 @@ type: External network', in the HyperV virtual network switch configuration. this is still a work in progress. Till the support is complete we recommend disabling TX/RX offloads for both the VM's as well as the HyperV. +Windows Services +---------------- +Open vSwitch daemons come with support to run as a Windows service. The +instructions here assume that you have installed the Open vSwitch utilities +and daemons via 'make install'. The commands shown here can be run from +MSYS bash or Windows command prompt. + +* Create the database. + + % ovsdb-tool create C:/openvswitch/etc/openvswitch/conf.db \ + "C:/openvswitch/usr/share/openvswitch/vswitch.ovsschema" + +* Create the ovsdb-server service and start it. + + % sc create ovsdb-server binpath="C:/Shares/openvswitch/ovsdb/ovsdb-server.exe C:/openvswitch/etc/openvswitch/conf.db -vfile:info --log-file --pidfile --remote=punix:db.sock --service --service-monitor" + + One of the common issues with creating a Windows service is with mungled + paths. You can make sure that the correct path has been registered with + the Windows services manager by running: + + % sc qc ovsdb-server + + Start the service. + + % sc start ovsdb-server + + Check that the service is healthy by running: + + % sc query ovsdb-server + +* Initialize the database. + + % ovs-vsctl --no-wait init + +* Create the ovs-vswitchd service and start it. + + % sc create ovs-vswitchd binpath="C:/Shares/openvswitch/vswitchd/ovs-vswitchd.exe --pidfile -vfile:info --log-file --service --service-monitor" + + % sc start ovs-vswitchd + + Check that the service is healthy by running: + + % sc query ovs-vswitchd + +* To stop and delete the services, run: + + % sc stop ovs-vswitchd + % sc stop ovsdb-server + % sc delete ovs-vswitchd + % sc delete ovsdb-server + Windows autobuild service ------------------------- AppVeyor (appveyor.com) provides a free Windows autobuild service for -- cgit v1.2.1 From d625fbd13ec3254981df5000bf2587d715401f36 Mon Sep 17 00:00:00 2001 From: Jesse Gross Date: Tue, 7 Apr 2015 17:45:40 -0700 Subject: tunneling: Convert tunnel push/pop functions to act on single packets. The userspace tunneling API for pushing and popping tunnel headers is currently based on processing batches of packets. However, there is no obvious way to take advantage of batching for these operations and so each tunnel operation has a pair of loops to process the batch. This changes the API to operate on single packets to enable better code reuse. Signed-off-by: Jesse Gross Acked-by: Pravin B Shelar --- lib/netdev-provider.h | 8 ++- lib/netdev-vport.c | 135 ++++++++++---------------------------------------- lib/netdev.c | 34 ++++++++++--- 3 files changed, 56 insertions(+), 121 deletions(-) diff --git a/lib/netdev-provider.h b/lib/netdev-provider.h index fabeb2d41..734601d84 100644 --- a/lib/netdev-provider.h +++ b/lib/netdev-provider.h @@ -264,14 +264,12 @@ struct netdev_class { * flow. Push header is called for packet to build header specific to * a packet on actual transmit. It uses partial header build by * build_header() which is passed as data. */ - int (*push_header)(const struct netdev *netdev, - struct dp_packet **buffers, int cnt, - const struct ovs_action_push_tnl *data); + void (*push_header)(struct dp_packet *packet, + const struct ovs_action_push_tnl *data); /* Pop tunnel header from packet, build tunnel metadata and resize packet * for further processing. */ - int (*pop_header)(struct netdev *netdev, - struct dp_packet **buffers, int cnt); + int (*pop_header)(struct dp_packet *packet); /* Returns the id of the numa node the 'netdev' is on. If there is no * such info, returns NETDEV_NUMA_UNSPEC. */ diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c index 23483e3fe..f228ac219 100644 --- a/lib/netdev-vport.c +++ b/lib/netdev-vport.c @@ -920,13 +920,14 @@ get_src_port(struct dp_packet *packet) tnl_udp_port_min); } -static void * -push_udp_header(struct dp_packet *packet, const void *header, int size) +static void +push_udp_header(struct dp_packet *packet, + const struct ovs_action_push_tnl *data) { struct udp_header *udp; int ip_tot_size; - udp = push_ip_header(packet, header, size, &ip_tot_size); + udp = push_ip_header(packet, data->header, data->header_len, &ip_tot_size); /* set udp src port */ udp->udp_src = get_src_port(packet); @@ -943,8 +944,6 @@ push_udp_header(struct dp_packet *packet, const void *header, int size) udp->udp_csum = htons(0xffff); } } - - return udp + 1; } static void * @@ -1042,14 +1041,8 @@ parse_gre_header(struct dp_packet *packet, return hlen; } -static void -reset_tnl_md(struct pkt_metadata *md) -{ - memset(&md->tunnel, 0, sizeof(md->tunnel)); -} - -static void -gre_extract_md(struct dp_packet *packet) +static int +netdev_gre_pop_header(struct dp_packet *packet) { struct pkt_metadata *md = &packet->md; struct flow_tnl *tnl = &md->tunnel; @@ -1058,37 +1051,27 @@ gre_extract_md(struct dp_packet *packet) memset(md, 0, sizeof *md); if (hlen > dp_packet_size(packet)) { - return; + return EINVAL; } hlen = parse_gre_header(packet, tnl); if (hlen < 0) { - reset_tnl_md(md); + return -hlen; } dp_packet_reset_packet(packet, hlen); -} -static int -netdev_gre_pop_header(struct netdev *netdev_ OVS_UNUSED, - struct dp_packet **pkt, int cnt) -{ - int i; - - for (i = 0; i < cnt; i++) { - gre_extract_md(pkt[i]); - } return 0; } static void -netdev_gre_push_header__(struct dp_packet *packet, - const void *header, int size) +netdev_gre_push_header(struct dp_packet *packet, + const struct ovs_action_push_tnl *data) { struct gre_base_hdr *greh; int ip_tot_size; - greh = push_ip_header(packet, header, size, &ip_tot_size); + greh = push_ip_header(packet, data->header, data->header_len, &ip_tot_size); if (greh->flags & htons(GRE_CSUM)) { ovs_be16 *csum_opt = (ovs_be16 *) (greh + 1); @@ -1096,21 +1079,6 @@ netdev_gre_push_header__(struct dp_packet *packet, } } -static int -netdev_gre_push_header(const struct netdev *netdev OVS_UNUSED, - struct dp_packet **packets, int cnt, - const struct ovs_action_push_tnl *data) -{ - int i; - - for (i = 0; i < cnt; i++) { - netdev_gre_push_header__(packets[i], data->header, data->header_len); - packets[i]->md = PKT_METADATA_INITIALIZER(u32_to_odp(data->out_port)); - } - return 0; -} - - static int netdev_gre_build_header(const struct netdev *netdev, struct ovs_action_push_tnl *data, @@ -1158,8 +1126,8 @@ netdev_gre_build_header(const struct netdev *netdev, return 0; } -static void -vxlan_extract_md(struct dp_packet *packet) +static int +netdev_vxlan_pop_header(struct dp_packet *packet) { struct pkt_metadata *md = &packet->md; struct flow_tnl *tnl = &md->tunnel; @@ -1167,12 +1135,12 @@ vxlan_extract_md(struct dp_packet *packet) memset(md, 0, sizeof *md); if (VXLAN_HLEN > dp_packet_size(packet)) { - return; + return EINVAL; } vxh = udp_extract_tnl_md(packet, tnl); if (!vxh) { - return; + return EINVAL; } if (get_16aligned_be32(&vxh->vx_flags) != htonl(VXLAN_FLAGS) || @@ -1180,24 +1148,13 @@ vxlan_extract_md(struct dp_packet *packet) VLOG_WARN_RL(&err_rl, "invalid vxlan flags=%#x vni=%#x\n", ntohl(get_16aligned_be32(&vxh->vx_flags)), ntohl(get_16aligned_be32(&vxh->vx_vni))); - reset_tnl_md(md); - return; + return EINVAL; } tnl->tun_id = htonll(ntohl(get_16aligned_be32(&vxh->vx_vni)) >> 8); tnl->flags |= FLOW_TNL_F_KEY; dp_packet_reset_packet(packet, VXLAN_HLEN); -} -static int -netdev_vxlan_pop_header(struct netdev *netdev_ OVS_UNUSED, - struct dp_packet **pkt, int cnt) -{ - int i; - - for (i = 0; i < cnt; i++) { - vxlan_extract_md(pkt[i]); - } return 0; } @@ -1226,21 +1183,7 @@ netdev_vxlan_build_header(const struct netdev *netdev, } static int -netdev_vxlan_push_header(const struct netdev *netdev OVS_UNUSED, - struct dp_packet **packets, int cnt, - const struct ovs_action_push_tnl *data) -{ - int i; - - for (i = 0; i < cnt; i++) { - push_udp_header(packets[i], data->header, VXLAN_HLEN); - packets[i]->md = PKT_METADATA_INITIALIZER(u32_to_odp(data->out_port)); - } - return 0; -} - -static void -geneve_extract_md(struct dp_packet *packet) +netdev_geneve_pop_header(struct dp_packet *packet) { struct pkt_metadata *md = &packet->md; struct flow_tnl *tnl = &md->tunnel; @@ -1251,40 +1194,36 @@ geneve_extract_md(struct dp_packet *packet) if (GENEVE_BASE_HLEN > dp_packet_size(packet)) { VLOG_WARN_RL(&err_rl, "geneve packet too small: min header=%u packet size=%u\n", (unsigned int)GENEVE_BASE_HLEN, dp_packet_size(packet)); - return; + return EINVAL; } gnh = udp_extract_tnl_md(packet, tnl); if (!gnh) { - return; + return EINVAL; } hlen = GENEVE_BASE_HLEN + gnh->opt_len * 4; if (hlen > dp_packet_size(packet)) { VLOG_WARN_RL(&err_rl, "geneve packet too small: header len=%u packet size=%u\n", hlen, dp_packet_size(packet)); - reset_tnl_md(md); - return; + return EINVAL; } if (gnh->ver != 0) { VLOG_WARN_RL(&err_rl, "unknown geneve version: %"PRIu8"\n", gnh->ver); - reset_tnl_md(md); - return; + return EINVAL; } if (gnh->opt_len && gnh->critical) { VLOG_WARN_RL(&err_rl, "unknown geneve critical options: %"PRIu8" bytes\n", gnh->opt_len * 4); - reset_tnl_md(md); - return; + return EINVAL; } if (gnh->proto_type != htons(ETH_TYPE_TEB)) { VLOG_WARN_RL(&err_rl, "unknown geneve encapsulated protocol: %#x\n", ntohs(gnh->proto_type)); - reset_tnl_md(md); - return; + return EINVAL; } tnl->flags |= gnh->oam ? FLOW_TNL_F_OAM : 0; @@ -1292,17 +1231,7 @@ geneve_extract_md(struct dp_packet *packet) tnl->flags |= FLOW_TNL_F_KEY; dp_packet_reset_packet(packet, hlen); -} - -static int -netdev_geneve_pop_header(struct netdev *netdev_ OVS_UNUSED, - struct dp_packet **pkt, int cnt) -{ - int i; - for (i = 0; i < cnt; i++) { - geneve_extract_md(pkt[i]); - } return 0; } @@ -1331,20 +1260,6 @@ netdev_geneve_build_header(const struct netdev *netdev, return 0; } -static int -netdev_geneve_push_header(const struct netdev *netdev OVS_UNUSED, - struct dp_packet **packets, int cnt, - const struct ovs_action_push_tnl *data) -{ - int i; - - for (i = 0; i < cnt; i++) { - push_udp_header(packets[i], data->header, data->header_len); - packets[i]->md = PKT_METADATA_INITIALIZER(u32_to_odp(data->out_port)); - } - return 0; -} - static void netdev_vport_range(struct unixctl_conn *conn, int argc, const char *argv[], void *aux OVS_UNUSED) @@ -1475,7 +1390,7 @@ netdev_vport_tunnel_register(void) * a port number to the end if one is necessary. */ static const struct vport_class vport_classes[] = { TUNNEL_CLASS("geneve", "genev_sys", netdev_geneve_build_header, - netdev_geneve_push_header, + push_udp_header, netdev_geneve_pop_header), TUNNEL_CLASS("gre", "gre_sys", netdev_gre_build_header, netdev_gre_push_header, @@ -1484,7 +1399,7 @@ netdev_vport_tunnel_register(void) TUNNEL_CLASS("gre64", "gre64_sys", NULL, NULL, NULL), TUNNEL_CLASS("ipsec_gre64", "gre64_sys", NULL, NULL, NULL), TUNNEL_CLASS("vxlan", "vxlan_sys", netdev_vxlan_build_header, - netdev_vxlan_push_header, + push_udp_header, netdev_vxlan_pop_header), TUNNEL_CLASS("lisp", "lisp_sys", NULL, NULL, NULL) }; diff --git a/lib/netdev.c b/lib/netdev.c index c1d9b8fa5..9d391634b 100644 --- a/lib/netdev.c +++ b/lib/netdev.c @@ -34,6 +34,7 @@ #include "netdev-dpdk.h" #include "netdev-provider.h" #include "netdev-vport.h" +#include "odp-netlink.h" #include "openflow/openflow.h" #include "packets.h" #include "poll-loop.h" @@ -735,9 +736,23 @@ netdev_send(struct netdev *netdev, int qid, struct dp_packet **buffers, int netdev_pop_header(struct netdev *netdev, struct dp_packet **buffers, int cnt) { - return (netdev->netdev_class->pop_header - ? netdev->netdev_class->pop_header(netdev, buffers, cnt) - : EOPNOTSUPP); + int i; + + if (!netdev->netdev_class->pop_header) { + return EOPNOTSUPP; + } + + for (i = 0; i < cnt; i++) { + int err; + + err = netdev->netdev_class->pop_header(buffers[i]); + if (err) { + struct flow_tnl *tunnel_md = &buffers[i]->md.tunnel; + memset(tunnel_md, 0, sizeof *tunnel_md); + } + } + + return 0; } int @@ -755,11 +770,18 @@ netdev_push_header(const struct netdev *netdev, struct dp_packet **buffers, int cnt, const struct ovs_action_push_tnl *data) { - if (netdev->netdev_class->push_header) { - return netdev->netdev_class->push_header(netdev, buffers, cnt, data); - } else { + int i; + + if (!netdev->netdev_class->push_header) { return -EINVAL; } + + for (i = 0; i < cnt; i++) { + netdev->netdev_class->push_header(buffers[i], data); + buffers[i]->md = PKT_METADATA_INITIALIZER(u32_to_odp(data->out_port)); + } + + return 0; } /* Registers with the poll loop to wake up from the next call to poll_block() -- cgit v1.2.1 From e62d903bca43235e5c92ded0753b1c13096e790a Mon Sep 17 00:00:00 2001 From: Jesse Gross Date: Wed, 8 Apr 2015 12:56:50 -0700 Subject: tunneling: Invalid packets should be cleared. If we receive a packet with an invalid tunnel header, we should drop the packet without further processing. Currently we do this by removing any parsed tunnel metadata. However, this is not sufficient to stop processing - this only results in the packet getting dropped by chance when something usually runs across part of the packet that does not make sense. Since both the packet and its metadata are in an inconsistent state, it's also possible that the result is an ovs-vswitchd crash or forwarding of a mangled packet. Rather than clear the metadata, an alternate solution is to remove all of the packet data. This guarantees that the packet gets dropped during the next round of processing. Signed-off-by: Jesse Gross Acked-by: Pravin B Shelar --- lib/netdev.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/netdev.c b/lib/netdev.c index 9d391634b..45f7f29a0 100644 --- a/lib/netdev.c +++ b/lib/netdev.c @@ -747,8 +747,7 @@ netdev_pop_header(struct netdev *netdev, struct dp_packet **buffers, int cnt) err = netdev->netdev_class->pop_header(buffers[i]); if (err) { - struct flow_tnl *tunnel_md = &buffers[i]->md.tunnel; - memset(tunnel_md, 0, sizeof *tunnel_md); + dp_packet_clear(buffers[i]); } } -- cgit v1.2.1 From b13c9440d4e5e561ec4df011f1d62fffec5a8a66 Mon Sep 17 00:00:00 2001 From: Jesse Gross Date: Tue, 7 Apr 2015 16:11:23 -0700 Subject: datapath: Account for "udptunnels: Call handle_offloads after inserting vlan tag." Upstream commit: udptunnels: Call handle_offloads after inserting vlan tag. handle_offloads() calls skb_reset_inner_headers() to store the layer pointers to the encapsulated packet. However, we currently push the vlag tag (if there is one) onto the packet afterwards. This changes the MAC header for the encapsulated packet but it is not reflected in skb->inner_mac_header, which breaks GSO and drivers which attempt to use this for encapsulation offloads. Fixes: b736a623 ("vxlan: Add tx-vlan offload support.") Signed-off-by: Jesse Gross Signed-off-by: David S. Miller Upstream: 4aac884d ("udptunnels: Call handle_offloads after inserting vlan tag.") Signed-off-by: Jesse Gross Acked-by: Pravin B Shelar --- datapath/linux/compat/geneve.c | 8 ++++---- datapath/linux/compat/vxlan.c | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/datapath/linux/compat/geneve.c b/datapath/linux/compat/geneve.c index 5fc6c6761..48a306e93 100644 --- a/datapath/linux/compat/geneve.c +++ b/datapath/linux/compat/geneve.c @@ -91,10 +91,6 @@ int geneve_xmit_skb(struct geneve_sock *gs, struct rtable *rt, int min_headroom; int err; - skb = udp_tunnel_handle_offloads(skb, csum, (opt_len == 0)); - if (IS_ERR(skb)) - return PTR_ERR(skb); - min_headroom = LL_RESERVED_SPACE(rt_dst(rt).dev) + rt_dst(rt).header_len + GENEVE_BASE_HLEN + opt_len + sizeof(struct iphdr) + (skb_vlan_tag_present(skb) ? VLAN_HLEN : 0); @@ -109,6 +105,10 @@ int geneve_xmit_skb(struct geneve_sock *gs, struct rtable *rt, if (unlikely(!skb)) return -ENOMEM; + skb = udp_tunnel_handle_offloads(skb, csum, (opt_len == 0)); + if (IS_ERR(skb)) + return PTR_ERR(skb); + gnvh = (struct genevehdr *)__skb_push(skb, sizeof(*gnvh) + opt_len); geneve_build_header(gnvh, tun_flags, vni, opt_len, opt); diff --git a/datapath/linux/compat/vxlan.c b/datapath/linux/compat/vxlan.c index 8af3433ff..51135fac7 100644 --- a/datapath/linux/compat/vxlan.c +++ b/datapath/linux/compat/vxlan.c @@ -191,10 +191,6 @@ int vxlan_xmit_skb(struct vxlan_sock *vs, int err; bool udp_sum = !!(vxflags & VXLAN_F_UDP_CSUM); - skb = udp_tunnel_handle_offloads(skb, udp_sum, true); - if (IS_ERR(skb)) - return PTR_ERR(skb); - min_headroom = LL_RESERVED_SPACE(rt_dst(rt).dev) + rt_dst(rt).header_len + VXLAN_HLEN + sizeof(struct iphdr) + (skb_vlan_tag_present(skb) ? VLAN_HLEN : 0); @@ -210,6 +206,10 @@ int vxlan_xmit_skb(struct vxlan_sock *vs, if (WARN_ON(!skb)) return -ENOMEM; + skb = udp_tunnel_handle_offloads(skb, udp_sum, true); + if (IS_ERR(skb)) + return PTR_ERR(skb); + vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh)); vxh->vx_flags = htonl(VXLAN_HF_VNI); vxh->vx_vni = md->vni; -- cgit v1.2.1 From 60fc3b7ba4c0dccc9799c7cec6cc77c0d19aa17a Mon Sep 17 00:00:00 2001 From: Daniele Di Proietto Date: Tue, 7 Apr 2015 20:02:13 +0100 Subject: dpif-netdev: Group statistics updates in the slow path. Since statistics updates might require locking (in future commits) grouping them will reduce the locking overhead. Signed-off-by: Daniele Di Proietto Acked-by: Ethan Jackson --- lib/dpif-netdev.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 15bc7f932..b5cfdcb7b 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -2701,10 +2701,6 @@ dp_netdev_upcall(struct dp_netdev_pmd_thread *pmd, struct dp_packet *packet_, { struct dp_netdev *dp = pmd->dp; - if (type == DPIF_UC_MISS) { - dp_netdev_count_packet(pmd, DP_STAT_MISS, 1); - } - if (OVS_UNLIKELY(!dp->upcall_cb)) { return ENODEV; } @@ -2916,6 +2912,7 @@ fast_path_processing(struct dp_netdev_pmd_thread *pmd, if (OVS_UNLIKELY(any_miss) && !fat_rwlock_tryrdlock(&dp->upcall_rwlock)) { uint64_t actions_stub[512 / 8], slow_stub[512 / 8]; struct ofpbuf actions, put_actions; + int miss_cnt = 0, lost_cnt = 0; ovs_u128 ufid; ofpbuf_use_stub(&actions, actions_stub, sizeof actions_stub); @@ -2940,6 +2937,8 @@ fast_path_processing(struct dp_netdev_pmd_thread *pmd, continue; } + miss_cnt++; + miniflow_expand(&keys[i].mf, &match.flow); ofpbuf_clear(&actions); @@ -2951,7 +2950,7 @@ fast_path_processing(struct dp_netdev_pmd_thread *pmd, &put_actions); if (OVS_UNLIKELY(error && error != ENOSPC)) { dp_packet_delete(packets[i]); - dp_netdev_count_packet(pmd, DP_STAT_LOST, 1); + lost_cnt++; continue; } @@ -2985,6 +2984,8 @@ fast_path_processing(struct dp_netdev_pmd_thread *pmd, ofpbuf_uninit(&actions); ofpbuf_uninit(&put_actions); fat_rwlock_unlock(&dp->upcall_rwlock); + dp_netdev_count_packet(pmd, DP_STAT_MISS, miss_cnt); + dp_netdev_count_packet(pmd, DP_STAT_LOST, lost_cnt); } else if (OVS_UNLIKELY(any_miss)) { int dropped_cnt = 0; -- cgit v1.2.1 From eb94da30aeb32cb004c85945a593e3e5c96d0b03 Mon Sep 17 00:00:00 2001 From: Daniele Di Proietto Date: Tue, 7 Apr 2015 20:02:14 +0100 Subject: dpif-netdev: Make datapath and flow stats atomic. A read operation from a non atomic shared value (without external locking) can return incorrect values. Using the atomic semantics prevents this from happening. However: * No memory barriers are used. We don't need that kind of consistency for statistics (we use relaxed operations). * The updates are not atomic, just the loads and stores. This is ok because there's a single writer. Signed-off-by: Daniele Di Proietto Acked-by: Ethan Jackson --- lib/dpif-netdev.c | 72 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 53 insertions(+), 19 deletions(-) diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index b5cfdcb7b..a161e9806 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -239,10 +239,10 @@ struct dp_netdev_port { /* Contained by struct dp_netdev_flow's 'stats' member. */ struct dp_netdev_flow_stats { - long long int used; /* Last used time, in monotonic msecs. */ - long long int packet_count; /* Number of packets matched. */ - long long int byte_count; /* Number of bytes matched. */ - uint16_t tcp_flags; /* Bitwise-OR of seen tcp_flags values. */ + atomic_llong used; /* Last used time, in monotonic msecs. */ + atomic_ullong packet_count; /* Number of packets matched. */ + atomic_ullong byte_count; /* Number of bytes matched. */ + atomic_uint16_t tcp_flags; /* Bitwise-OR of seen tcp_flags values. */ }; /* A flow in 'dp_netdev_pmd_thread's 'flow_table'. @@ -338,7 +338,7 @@ static void dp_netdev_actions_free(struct dp_netdev_actions *); /* Contained by struct dp_netdev_pmd_thread's 'stats' member. */ struct dp_netdev_pmd_stats { /* Indexed by DP_STAT_*. */ - unsigned long long int n[DP_N_STATS]; + atomic_ullong n[DP_N_STATS]; }; /* PMD: Poll modes drivers. PMD accesses devices via polling to eliminate @@ -746,6 +746,21 @@ dpif_netdev_destroy(struct dpif *dpif) return 0; } +/* Add 'n' to the atomic variable 'var' non-atomically and using relaxed + * load/store semantics. While the increment is not atomic, the load and + * store operations are, making it impossible to read inconsistent values. + * + * This is used to update thread local stats counters. */ +static void +non_atomic_ullong_add(atomic_ullong *var, unsigned long long n) +{ + unsigned long long tmp; + + atomic_read_relaxed(var, &tmp); + tmp += n; + atomic_store_relaxed(var, tmp); +} + static int dpif_netdev_get_stats(const struct dpif *dpif, struct dpif_dp_stats *stats) { @@ -754,10 +769,15 @@ dpif_netdev_get_stats(const struct dpif *dpif, struct dpif_dp_stats *stats) stats->n_flows = stats->n_hit = stats->n_missed = stats->n_lost = 0; CMAP_FOR_EACH (pmd, node, &dp->poll_threads) { + unsigned long long n; stats->n_flows += cmap_count(&pmd->flow_table); - stats->n_hit += pmd->stats.n[DP_STAT_HIT]; - stats->n_missed += pmd->stats.n[DP_STAT_MISS]; - stats->n_lost += pmd->stats.n[DP_STAT_LOST]; + + atomic_read_relaxed(&pmd->stats.n[DP_STAT_HIT], &n); + stats->n_hit += n; + atomic_read_relaxed(&pmd->stats.n[DP_STAT_MISS], &n); + stats->n_missed += n; + atomic_read_relaxed(&pmd->stats.n[DP_STAT_LOST], &n); + stats->n_lost += n; } stats->n_masks = UINT32_MAX; stats->n_mask_hit = UINT64_MAX; @@ -1545,13 +1565,24 @@ dp_netdev_pmd_find_flow(const struct dp_netdev_pmd_thread *pmd, } static void -get_dpif_flow_stats(const struct dp_netdev_flow *netdev_flow, +get_dpif_flow_stats(const struct dp_netdev_flow *netdev_flow_, struct dpif_flow_stats *stats) { - stats->n_packets = netdev_flow->stats.packet_count; - stats->n_bytes = netdev_flow->stats.byte_count; - stats->used = netdev_flow->stats.used; - stats->tcp_flags = netdev_flow->stats.tcp_flags; + struct dp_netdev_flow *netdev_flow; + unsigned long long n; + long long used; + uint16_t flags; + + netdev_flow = CONST_CAST(struct dp_netdev_flow *, netdev_flow_); + + atomic_read_relaxed(&netdev_flow->stats.packet_count, &n); + stats->n_packets = n; + atomic_read_relaxed(&netdev_flow->stats.byte_count, &n); + stats->n_bytes = n; + atomic_read_relaxed(&netdev_flow->stats.used, &used); + stats->used = used; + atomic_read_relaxed(&netdev_flow->stats.tcp_flags, &flags); + stats->tcp_flags = flags; } /* Converts to the dpif_flow format, using 'key_buf' and 'mask_buf' for @@ -2678,19 +2709,22 @@ static void dp_netdev_flow_used(struct dp_netdev_flow *netdev_flow, int cnt, int size, uint16_t tcp_flags) { - long long int now = time_msec(); + long long now = time_msec(); + uint16_t flags; - netdev_flow->stats.used = MAX(now, netdev_flow->stats.used); - netdev_flow->stats.packet_count += cnt; - netdev_flow->stats.byte_count += size; - netdev_flow->stats.tcp_flags |= tcp_flags; + atomic_store_relaxed(&netdev_flow->stats.used, now); + non_atomic_ullong_add(&netdev_flow->stats.packet_count, cnt); + non_atomic_ullong_add(&netdev_flow->stats.byte_count, size); + atomic_read_relaxed(&netdev_flow->stats.tcp_flags, &flags); + flags |= tcp_flags; + atomic_store_relaxed(&netdev_flow->stats.tcp_flags, flags); } static void dp_netdev_count_packet(struct dp_netdev_pmd_thread *pmd, enum dp_stat_type type, int cnt) { - pmd->stats.n[type] += cnt; + non_atomic_ullong_add(&pmd->stats.n[type], cnt); } static int -- cgit v1.2.1 From abcf3ef4c3f75963f46a11501685363e3ceb7c0e Mon Sep 17 00:00:00 2001 From: Daniele Di Proietto Date: Tue, 7 Apr 2015 20:02:15 +0100 Subject: dpif-netdev: Count exact match cache hits. We used to count exact match cache hits and masked classifier hits together. This commit splits the DP_STAT_HIT counter into two. This change will be used by future commits. Signed-off-by: Daniele Di Proietto Acked-by: Ethan Jackson --- lib/dpif-netdev.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index a161e9806..61d9211c2 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -220,7 +220,8 @@ static struct dp_netdev_port *dp_netdev_lookup_port(const struct dp_netdev *dp, odp_port_t); enum dp_stat_type { - DP_STAT_HIT, /* Packets that matched in the flow table. */ + DP_STAT_EXACT_HIT, /* Packets that had an exact match (emc). */ + DP_STAT_MASKED_HIT, /* Packets that matched in the flow table. */ DP_STAT_MISS, /* Packets that did not match. */ DP_STAT_LOST, /* Packets not passed up to the client. */ DP_N_STATS @@ -772,7 +773,9 @@ dpif_netdev_get_stats(const struct dpif *dpif, struct dpif_dp_stats *stats) unsigned long long n; stats->n_flows += cmap_count(&pmd->flow_table); - atomic_read_relaxed(&pmd->stats.n[DP_STAT_HIT], &n); + atomic_read_relaxed(&pmd->stats.n[DP_STAT_MASKED_HIT], &n); + stats->n_hit += n; + atomic_read_relaxed(&pmd->stats.n[DP_STAT_EXACT_HIT], &n); stats->n_hit += n; atomic_read_relaxed(&pmd->stats.n[DP_STAT_MISS], &n); stats->n_missed += n; @@ -2810,7 +2813,8 @@ packet_batch_init(struct packet_batch *batch, struct dp_netdev_flow *flow) static inline void packet_batch_execute(struct packet_batch *batch, - struct dp_netdev_pmd_thread *pmd) + struct dp_netdev_pmd_thread *pmd, + enum dp_stat_type hit_type) { struct dp_netdev_actions *actions; struct dp_netdev_flow *flow = batch->flow; @@ -2823,7 +2827,7 @@ packet_batch_execute(struct packet_batch *batch, dp_netdev_execute_actions(pmd, batch->packets, batch->packet_count, true, actions->actions, actions->size); - dp_netdev_count_packet(pmd, DP_STAT_HIT, batch->packet_count); + dp_netdev_count_packet(pmd, hit_type, batch->packet_count); } static inline bool @@ -2914,7 +2918,7 @@ emc_processing(struct dp_netdev_pmd_thread *pmd, struct dp_packet **packets, } for (i = 0; i < n_batches; i++) { - packet_batch_execute(&batches[i], pmd); + packet_batch_execute(&batches[i], pmd, DP_STAT_EXACT_HIT); } return notfound_cnt; @@ -3051,7 +3055,7 @@ fast_path_processing(struct dp_netdev_pmd_thread *pmd, } for (i = 0; i < n_batches; i++) { - packet_batch_execute(&batches[i], pmd); + packet_batch_execute(&batches[i], pmd, DP_STAT_MASKED_HIT); } } -- cgit v1.2.1 From 2f86335b8a143a475ab44492ca18927876e36a0c Mon Sep 17 00:00:00 2001 From: Flavio Leitner Date: Fri, 10 Apr 2015 11:07:50 -0300 Subject: test-csum: endianess fix The math is done in network byte order so the 32 bits won't match between big and little endian, so the assert fails. Reduce to 16 bits and then compare to the converted constant. Signed-off-by: Flavio Leitner Signed-off-by: Jesse Gross --- tests/test-csum.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/test-csum.c b/tests/test-csum.c index 2685f679c..97638b916 100644 --- a/tests/test-csum.c +++ b/tests/test-csum.c @@ -181,6 +181,7 @@ test_crc32c(void) static void test_pseudo(void) { + ovs_be16 csum; /* Try an IP header similar to one that the tunnel code * might generate. */ struct ip_header ip = { @@ -196,12 +197,14 @@ test_pseudo(void) .ip_dst = { .hi = htons(0x1400), .lo = htons(0x0001) } }; - assert(packet_csum_pseudoheader(&ip) == 0x8628); + csum = csum_finish(packet_csum_pseudoheader(&ip)); + assert(csum == htons(0xd779)); /* And also test something totally different to check for * corner cases. */ memset(&ip, 0xff, sizeof ip); - assert(packet_csum_pseudoheader(&ip) == 0x5c2fb); + csum = csum_finish(packet_csum_pseudoheader(&ip)); + assert(csum == htons(0xff3c)); mark('#'); } -- cgit v1.2.1 From e8fe6ad03aa3d25b5ae99190d5aa065705a1b3c8 Mon Sep 17 00:00:00 2001 From: Flavio Leitner Date: Fri, 10 Apr 2015 11:08:10 -0300 Subject: tests: gre: fix flags endianness The flags field is 16 bits so use network byte order in the test case and use the proper conversion methods when parsing and dumping. Signed-off-by: Flavio Leitner Signed-off-by: Jesse Gross --- lib/odp-util.c | 7 ++++--- tests/odp.at | 4 ++-- tests/tunnel-push-pop.at | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/odp-util.c b/lib/odp-util.c index 8a81f6b47..b82edb700 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -577,7 +577,7 @@ format_odp_tnl_push_header(struct ds *ds, struct ovs_action_push_tnl *data) greh = (const struct gre_base_hdr *) l4; ds_put_format(ds, "gre((flags=0x%"PRIx16",proto=0x%"PRIx16")", - greh->flags, ntohs(greh->protocol)); + ntohs(greh->flags), ntohs(greh->protocol)); options = (ovs_16aligned_be32 *)(greh + 1); if (greh->flags & htons(GRE_CSUM)) { ds_put_format(ds, ",csum=0x%"PRIx16, ntohs(*((ovs_be16 *)options))); @@ -855,7 +855,7 @@ ovs_parse_tnl_push(const char *s, struct ovs_action_push_tnl *data) struct ip_header *ip; struct udp_header *udp; struct gre_base_hdr *greh; - uint16_t gre_proto, dl_type, udp_src, udp_dst, csum; + uint16_t gre_proto, gre_flags, dl_type, udp_src, udp_dst, csum; ovs_be32 sip, dip; uint32_t tnl_type = 0, header_len = 0; void *l3, *l4; @@ -937,9 +937,10 @@ ovs_parse_tnl_push(const char *s, struct ovs_action_push_tnl *data) return -EINVAL; } } else if (ovs_scan_len(s, &n, "gre((flags=0x%"SCNx16",proto=0x%"SCNx16")", - &greh->flags, &gre_proto)){ + &gre_flags, &gre_proto)){ tnl_type = OVS_VPORT_TYPE_GRE; + greh->flags = htons(gre_flags); greh->protocol = htons(gre_proto); ovs_16aligned_be32 *options = (ovs_16aligned_be32 *) (greh + 1); diff --git a/tests/odp.at b/tests/odp.at index d615891c4..c35648711 100644 --- a/tests/odp.at +++ b/tests/odp.at @@ -279,8 +279,8 @@ sample(sample=9.7%,actions(1,2,3,push_vlan(vid=1,pcp=2))) set(tunnel(tun_id=0xabcdef1234567890,src=1.1.1.1,dst=2.2.2.2,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(df,csum,key))) set(tunnel(tun_id=0xabcdef1234567890,src=1.1.1.1,dst=2.2.2.2,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(key))) tnl_pop(4) -tnl_push(tnl_port(4),header(size=42,type=3,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x40),gre((flags=0x20,proto=0x6558),key=0x1e241)),out_port(1)) -tnl_push(tnl_port(4),header(size=46,type=3,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x40),gre((flags=0xa0,proto=0x6558),csum=0x0,key=0x1e241)),out_port(1)) +tnl_push(tnl_port(4),header(size=42,type=3,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x40),gre((flags=0x2000,proto=0x6558),key=0x1e241)),out_port(1)) +tnl_push(tnl_port(4),header(size=46,type=3,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x40),gre((flags=0xa000,proto=0x6558),csum=0x0,key=0x1e241)),out_port(1)) tnl_push(tnl_port(6),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0x8000000,vni=0x1c7)),out_port(1)) tnl_push(tnl_port(6),header(size=50,type=5,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=6081,csum=0x0),geneve(oam,vni=0x1c7)),out_port(1)) tnl_push(tnl_port(6),header(size=50,type=5,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=6081,csum=0xffff),geneve(vni=0x1c7)),out_port(1)) diff --git a/tests/tunnel-push-pop.at b/tests/tunnel-push-pop.at index 72216efb2..877e417ad 100644 --- a/tests/tunnel-push-pop.at +++ b/tests/tunnel-push-pop.at @@ -81,7 +81,7 @@ dnl Check GRE tunnel push AT_CHECK([ovs-ofctl add-flow int-br action=3]) AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout]) AT_CHECK([tail -1 stdout], [0], - [Datapath actions: tnl_push(tnl_port(3),header(size=42,type=3,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x40),gre((flags=0x20,proto=0x6558),key=0x1c8)),out_port(100)) + [Datapath actions: tnl_push(tnl_port(3),header(size=42,type=3,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x40),gre((flags=0x2000,proto=0x6558),key=0x1c8)),out_port(100)) ]) dnl Check Geneve tunnel push -- cgit v1.2.1