On Thu, Sep 14, 2023 at 6:48 PM Numan Siddique <[email protected]> wrote:
> On Fri, Sep 8, 2023 at 8:12 AM Ales Musil <[email protected]> wrote: > > > > The release message indicates that the address is > > no longer in use. Simply reply with status code success > > without any special handling as we do not store the > > information about address being in use. > > > > Reported-at: https://bugzilla.redhat.com/2237855 > > Signed-off-by: Ales Musil <[email protected]> > > Hi Ales, > > I applied this patch to the main branch and also backported to > branch-23.09 (considering this as a bug fix). > > I also updated the NEWS entry for this > > diff --git a/NEWS b/NEWS > index 005afabb1..e7edecd1a 100644 > --- a/NEWS > +++ b/NEWS > @@ -23,6 +23,8 @@ OVN v23.09.0 - xx xxx xxxx > cap the time between when ovn-controller sends gARP packets. > - Introduce support for binding remote ports in ovn-northd if the CMS > sets > requested-chassis option for a remote logical switch port. > + - Added support to reply success for DHCPv6 Release messages. > + > > OVN v23.06.0 - 01 Jun 2023 > -------------------------- > Hi Numan, thank you. > > > Do you think we should backport to other branches too ? > For now we should be fine with 23.09. > > Numan > Regards, Ales > > > --- > > controller/pinctrl.c | 94 +++++++++++++++++------ > > lib/ovn-l7.h | 8 ++ > > tests/ovn.at | 174 ++++++++++++++++++++++++------------------- > > 3 files changed, 175 insertions(+), 101 deletions(-) > > > > diff --git a/controller/pinctrl.c b/controller/pinctrl.c > > index 1884e9f1b..ff5a3444c 100644 > > --- a/controller/pinctrl.c > > +++ b/controller/pinctrl.c > > @@ -2290,6 +2290,26 @@ exit: > > } > > } > > > > +static void > > +encode_dhcpv6_server_id_opt(struct ofpbuf *opts, struct eth_addr *mac) > > +{ > > + /* The Server Identifier option carries a DUID > > + * identifying a server between a client and a server. > > + * See RFC 3315 Sec 9 and Sec 22.3. > > + * > > + * We use DUID Based on Link-layer Address [DUID-LL]. > > + */ > > + struct dhcpv6_opt_server_id *server_id = > > + ofpbuf_put_zeros(opts, sizeof *server_id); > > + *server_id = (struct dhcpv6_opt_server_id) { > > + .opt.code = htons(DHCPV6_OPT_SERVER_ID_CODE), > > + .opt.len = htons(DHCP6_OPT_SERVER_ID_LEN - > DHCP6_OPT_HEADER_LEN), > > + .duid_type = htons(DHCPV6_DUID_LL), > > + .hw_type = htons(DHCPV6_HW_TYPE_ETH), > > + .mac = *mac > > + }; > > +} > > + > > static bool > > compose_out_dhcpv6_opts(struct ofpbuf *userdata, > > struct ofpbuf *out_dhcpv6_opts, > > @@ -2303,33 +2323,15 @@ compose_out_dhcpv6_opts(struct ofpbuf *userdata, > > } > > > > size_t size = ntohs(userdata_opt->len); > > - uint8_t *userdata_opt_data = ofpbuf_try_pull(userdata, size); > > + void *userdata_opt_data = ofpbuf_try_pull(userdata, size); > > if (!userdata_opt_data) { > > return false; > > } > > > > switch (ntohs(userdata_opt->code)) { > > case DHCPV6_OPT_SERVER_ID_CODE: > > - { > > - /* The Server Identifier option carries a DUID > > - * identifying a server between a client and a server. > > - * See RFC 3315 Sec 9 and Sec 22.3. > > - * > > - * We use DUID Based on Link-layer Address [DUID-LL]. > > - */ > > - struct dhcpv6_opt_server_id opt_server_id = { > > - .opt.code = htons(DHCPV6_OPT_SERVER_ID_CODE), > > - .opt.len = htons(size + 4), > > - .duid_type = htons(DHCPV6_DUID_LL), > > - .hw_type = htons(DHCPV6_HW_TYPE_ETH), > > - }; > > - memcpy(&opt_server_id.mac, userdata_opt_data, > > - sizeof(struct eth_addr)); > > - void *ptr = ofpbuf_put_zeros(out_dhcpv6_opts, > > - sizeof(struct > dhcpv6_opt_server_id)); > > - memcpy(ptr, &opt_server_id, sizeof(struct > dhcpv6_opt_server_id)); > > + encode_dhcpv6_server_id_opt(out_dhcpv6_opts, > userdata_opt_data); > > break; > > - } > > > > case DHCPV6_OPT_IA_ADDR_CODE: > > { > > @@ -2442,6 +2444,40 @@ compose_out_dhcpv6_opts(struct ofpbuf *userdata, > > return true; > > } > > > > +static bool > > +compose_dhcpv6_status(struct ofpbuf *userdata, struct ofpbuf *opts) > > +{ > > + while (userdata->size) { > > + struct dhcpv6_opt_header *userdata_opt = ofpbuf_try_pull( > > + userdata, sizeof *userdata_opt); > > + if (!userdata_opt) { > > + return false; > > + } > > + > > + size_t size = ntohs(userdata_opt->len); > > + void *userdata_opt_data = ofpbuf_try_pull(userdata, size); > > + if (!userdata_opt_data) { > > + return false; > > + } > > + > > + /* We care only about server id. Ignore everything else. */ > > + if (ntohs(userdata_opt->code) == DHCPV6_OPT_SERVER_ID_CODE) { > > + encode_dhcpv6_server_id_opt(opts, userdata_opt_data); > > + break; > > + } > > + } > > + > > + /* Put success status code to the end. */ > > + struct dhcpv6_opt_status *status = ofpbuf_put_zeros(opts, sizeof > *status); > > + *status = (struct dhcpv6_opt_status) { > > + .opt.code = htons(DHCPV6_OPT_STATUS_CODE), > > + .opt.len = htons(DHCP6_OPT_STATUS_LEN - DHCP6_OPT_HEADER_LEN), > > + .status_code = htons(DHCPV6_STATUS_CODE_SUCCESS), > > + }; > > + > > + return true; > > +} > > + > > /* Called with in the pinctrl_handler thread context. */ > > static void > > pinctrl_handle_put_dhcpv6_opts( > > @@ -2492,6 +2528,7 @@ pinctrl_handle_put_dhcpv6_opts( > > > > uint8_t out_dhcpv6_msg_type; > > uint8_t in_dhcpv6_msg_type = *in_dhcpv6_data; > > + bool status_only = false; > > switch (in_dhcpv6_msg_type) { > > case DHCPV6_MSG_TYPE_SOLICIT: > > out_dhcpv6_msg_type = DHCPV6_MSG_TYPE_ADVT; > > @@ -2504,11 +2541,15 @@ pinctrl_handle_put_dhcpv6_opts( > > out_dhcpv6_msg_type = DHCPV6_MSG_TYPE_REPLY; > > break; > > > > + case DHCPV6_MSG_TYPE_RELEASE: > > + out_dhcpv6_msg_type = DHCPV6_MSG_TYPE_REPLY; > > + status_only = true; > > + break; > > + > > default: > > /* Invalid or unsupported DHCPv6 message type */ > > goto exit; > > } > > - > > /* Skip 4 bytes (message type (1 byte) + transaction ID (3 bytes). > */ > > in_dhcpv6_data += 4; > > /* We need to extract IAID from the IA-NA option of the client's > DHCPv6 > > @@ -2574,8 +2615,15 @@ pinctrl_handle_put_dhcpv6_opts( > > struct ofpbuf out_dhcpv6_opts = > > OFPBUF_STUB_INITIALIZER(out_ofpacts_dhcpv6_opts_stub); > > > > - if (!compose_out_dhcpv6_opts(userdata, &out_dhcpv6_opts, > > - iaid, ipxe_req, fqdn_flags)) { > > + bool compose = false; > > + if (status_only) { > > + compose = compose_dhcpv6_status(userdata, &out_dhcpv6_opts); > > + } else { > > + compose = compose_out_dhcpv6_opts(userdata, &out_dhcpv6_opts, > iaid, > > + ipxe_req, fqdn_flags); > > + } > > + > > + if (!compose) { > > VLOG_WARN_RL(&rl, "Invalid userdata"); > > goto exit; > > } > > diff --git a/lib/ovn-l7.h b/lib/ovn-l7.h > > index 9dc331421..ad514a922 100644 > > --- a/lib/ovn-l7.h > > +++ b/lib/ovn-l7.h > > @@ -255,6 +255,7 @@ BUILD_ASSERT_DECL(DHCP_OPT_HEADER_LEN == > sizeof(struct dhcp_opt_header)); > > #define DHCPV6_MSG_TYPE_REBIND 6 > > > > #define DHCPV6_MSG_TYPE_REPLY 7 > > +#define DHCPV6_MSG_TYPE_RELEASE 8 > > #define DHCPV6_MSG_TYPE_DECLINE 9 > > #define DHCPV6_MSG_TYPE_INFO_REQ 11 > > > > @@ -274,6 +275,9 @@ BUILD_ASSERT_DECL(DHCP_OPT_HEADER_LEN == > sizeof(struct dhcp_opt_header)); > > #define DHCPV6_OPT_BOOT_FILE_URL 59 > > #define DHCPV6_OPT_BOOT_FILE_URL_ALT 254 > > > > +/* DHCPv6 Status codes */ > > +#define DHCPV6_STATUS_CODE_SUCCESS 0 > > + > > #define DHCPV6_OPT_SERVER_ID \ > > DHCP_OPTION("server_id", DHCPV6_OPT_SERVER_ID_CODE, "mac") > > > > @@ -301,11 +305,13 @@ BUILD_ASSERT_DECL(DHCP_OPT_HEADER_LEN == > sizeof(struct dhcp_opt_header)); > > #define DHCPV6_FQDN_FLAGS_O 1 << 1 > > #define DHCPV6_FQDN_FLAGS_N 1 << 2 > > > > +#define DHCP6_OPT_HEADER_LEN 4 > > OVS_PACKED( > > struct dhcpv6_opt_header { > > ovs_be16 code; > > ovs_be16 len; > > }); > > +BUILD_ASSERT_DECL(DHCP6_OPT_HEADER_LEN == sizeof(struct > dhcpv6_opt_header)); > > > > #define DHCP6_OPT_SERVER_ID_LEN 14 > > struct dhcpv6_opt_server_id { > > @@ -377,12 +383,14 @@ struct dhcpv6_opt_ia_prefix { > > struct in6_addr ipv6; > > }); > > > > +#define DHCP6_OPT_STATUS_LEN 6 > > OVS_PACKED( > > struct dhcpv6_opt_status { > > struct dhcpv6_opt_header opt; > > ovs_be16 status_code; > > uint8_t msg[]; > > }); > > +BUILD_ASSERT_DECL(DHCP6_OPT_STATUS_LEN == sizeof(struct > dhcpv6_opt_status)); > > > > #define DHCPV6_DUID_LL 3 > > #define DHCPV6_HW_TYPE_ETH 1 > > diff --git a/tests/ovn.at b/tests/ovn.at > > index 2576a659b..e127530f6 100644 > > --- a/tests/ovn.at > > +++ b/tests/ovn.at > > @@ -7292,6 +7292,9 @@ OVN_POPULATE_ARP > > wait_for_ports_up > > check ovn-nbctl --wait=hv sync > > > > +# Start with 0 because the first request will not have NXT_RESUME > > +n_resume=0 > > + > > trim_zeros() { > > sed 's/\(00\)\{1,\}$//' > > } > > @@ -7360,6 +7363,59 @@ test_dhcpv6() { > > fi > > > > as hv1 ovs-appctl netdev-dummy/receive hv1-vif$inport $request > > + OVS_WAIT_UNTIL([test $n_resume = `cat ofctl_monitor*.log | grep -c > NXT_RESUME`]) > > + n_resume=$((n_resume + 1)) > > +} > > + > > +test_dhcpv6_release() { > > + local inport=$1 src_mac=$2 src_lla=$3 offer_ip=$4 > > + > > + local ip_scapy="DHCP6OptIAAddress(addr='${offer_ip}', > preflft=0xffffffff, validlft=0xffffffff)" > > + local req_scapy="Ether(dst='00:00:00:10:00:01', src='${src_mac}')/ \ > > + IPv6(dst='ff02::1:2', src='${src_lla}')/ \ > > + UDP(sport=546, dport=547)/ \ > > + DHCP6(msgtype=8, trid=0x010203)/ \ > > + > DHCP6OptClientId(duid=DUID_LL(lladdr='${src_mac}'))/ \ > > + > DHCP6OptServerId(duid=DUID_LL(lladdr='00:00:00:10:00:01'))/ \ > > + DHCP6OptIA_NA(iaid=0x01020304, T1=0xffffffff, > T2=0xffffffff, ianaopts=[[${ip_scapy}]])" > > + > > + request=$(fmt_pkt "${req_scapy}") > > + > > + local rep_scapy="Ether(dst='${src_mac}', src='00:00:00:10:00:01')/ \ > > + IPv6(dst='${src_lla}', > src='fe80::0200:00ff:fe10:0001')/ \ > > + UDP(sport=547, dport=546)/ \ > > + DHCP6(msgtype=7, trid=0x010203)/ \ > > + > DHCP6OptClientId(duid=DUID_LL(lladdr='${src_mac}'))/ \ > > + > DHCP6OptServerId(duid=DUID_LL(lladdr='00:00:00:10:00:01'))/ \ > > + DHCP6OptStatusCode(statuscode=0)" > > + > > + reply=$(fmt_pkt "${rep_scapy}") > > + echo $reply | trim_zeros >> $inport.expected > > + > > + as hv1 ovs-appctl netdev-dummy/receive hv1-vif$inport $request > > + OVS_WAIT_UNTIL([test $n_resume = `cat ofctl_monitor*.log | grep -c > NXT_RESUME`]) > > + n_resume=$((n_resume + 1)) > > +} > > + > > +check_packets() { > > + local port=$1 > > + > > + $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif$port-tx.pcap | > trim_zeros > $port.packets > > + # Skipping UDP checksum > > + cat $port.expected | cut -c 1-120,125- > expout > > + AT_CHECK([cat $port.packets | cut -c 1-120,125- ], [0], [expout]) > > + > > + rm $port.packets > > + rm $port.expected > > +} > > + > > +check_empty_packets() { > > + local port=$1 > > + > > + $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif$port-tx.pcap | > trim_zeros > $port.packets > > + AT_CHECK([cat $port.packets], [0], []) > > + > > + rm $port.packets > > } > > > > AT_CAPTURE_FILE([ofctl_monitor0.log]) > > @@ -7381,23 +7437,31 @@ AT_CAPTURE_FILE([sbflows]) > > echo "------ hv1 dump ----------" > > as hv1 ovs-ofctl dump-flows br-int > > > > +# Send DHCPv6 packet on ls2-lp1. native DHCPv6 is disabled on this port. > > +# There should be no DHCPv6 reply from ovn-controller and the request > packet > > +# should be received by ls2-lp2. > > + > > +src_mac="f0:00:00:00:00:03" > > +src_lla="fe80::f200:00ff:fe00:0003" > > +test_dhcpv6 3 $src_mac $src_lla 1 0 "" "" 4 > > + > > +# vif3-tx.pcap should not have received the DHCPv6 reply packet > > +check_empty 3 > > + > > +# vif4-tx.pcap should have received the DHCPv6 request packet > > +check_packets 4 > > + > > src_mac="f0:00:00:00:00:01" > > src_lla="fe80::f200:00ff:fe00:0001" > > offer_ip="ae70::4" > > -test_dhcpv6 1 $src_mac $src_lla 1 $offer_ip "" "" > > > > -# NXT_RESUMEs should be 1. > > -OVS_WAIT_UNTIL([test 1 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) > > +test_dhcpv6 1 $src_mac $src_lla 1 $offer_ip "" "" > > +check_packets 1 > > > > -$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif1-tx.pcap | > trim_zeros > 1.packets > > -# cat 1.expected | trim_zeros > expout > > -cat 1.expected | cut -c -120 > expout > > -AT_CHECK([cat 1.packets | cut -c -120], [0], [expout]) > > -# Skipping the UDP checksum > > -cat 1.expected | cut -c 125- > expout > > -AT_CHECK([cat 1.packets | cut -c 125-], [0], [expout]) > > +reset_pcap_file hv1-vif1 hv1/vif1 > > > > -rm 1.expected > > +test_dhcpv6_release 1 $src_mac $src_lla $offer_ip > > +check_packets 1 > > > > # Send invalid packet on ls1-lp2. ovn-controller should resume the > packet > > # without any modifications and the packet should be received by > ls1-lp1. > > @@ -7414,70 +7478,29 @@ offer_ip="ae70::5" > > > > test_dhcpv6 2 $src_mac $src_lla 16 0 "" "" 1 1 > > > > -# NXT_RESUMEs should be 2. > > -OVS_WAIT_UNTIL([test 2 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) > > - > > # vif2-tx.pcap should not have received the DHCPv6 reply packet > > -rm 2.packets > > -$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap | > trim_zeros > 2.packets > > -AT_CHECK([cat 2.packets], [0], []) > > +check_empty 2 > > > > # vif1-tx.pcap should have received the DHCPv6 (invalid) request packet > > -$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif1-tx.pcap | > trim_zeros > 1.packets > > -cat 1.expected > expout > > -AT_CHECK([cat 1.packets], [0], [expout]) > > - > > -# Send DHCPv6 packet on ls2-lp1. native DHCPv6 is disabled on this port. > > -# There should be no DHCPv6 reply from ovn-controller and the request > packet > > -# should be received by ls2-lp2. > > - > > -src_mac="f0:00:00:00:00:03" > > -src_lla="fe80::f200:00ff:fe00:0003" > > -test_dhcpv6 3 $src_mac $src_lla 1 0 "" "" 4 > > - > > -# NXT_RESUMEs should be 2 only. > > -OVS_WAIT_UNTIL([test 2 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) > > - > > -# vif3-tx.pcap should not have received the DHCPv6 reply packet > > -$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif3-tx.pcap | > trim_zeros > 3.packets > > -AT_CHECK([cat 3.packets], [0], []) > > - > > -# vif4-tx.pcap should have received the DHCPv6 request packet > > -$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif4-tx.pcap | > trim_zeros > 4.packets > > -cat 4.expected > expout > > -AT_CHECK([cat 4.packets], [0], [expout]) > > +check_packets 1 > > > > # Send DHCPv6 packet on ls1-lp3. native DHCPv6 works as stateless mode > for this port. > > # The DHCPv6 reply shouldn't contain offer_ip. > > src_mac="f0:00:00:00:00:22" > > src_lla="fe80::f200:00ff:fe00:0022" > > reset_pcap_file hv1-vif5 hv1/vif5 > > -test_dhcpv6 5 $src_mac $src_lla 1 1 "" "" 5 > > > > -# NXT_RESUMEs should be 3. > > -OVS_WAIT_UNTIL([test 3 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) > > - > > -$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif5-tx.pcap | > trim_zeros > 5.packets > > -# Skipping the UDP checksum > > -cat 5.expected | cut -c 1-120,125- > expout > > -AT_CHECK([cat 5.packets | cut -c 1-120,125- ], [0], [expout]) > > +test_dhcpv6 5 $src_mac $src_lla 1 1 "" "" 5 > > +check_packets 5 > > > > # Send DHCPv6 information request (code 11) on ls1-lp3. The DHCPv6 reply > > # shouldn't contain offer_ip > > src_mac="f0:00:00:00:00:22" > > src_lla="fe80::f200:00ff:fe00:0022" > > reset_pcap_file hv1-vif5 hv1/vif5 > > -rm -f 5.expected > > -test_dhcpv6 5 $src_mac $src_lla 11 1 "" "" 5 > > > > -# NXT_RESUMEs should be 4. > > -OVS_WAIT_UNTIL([test 4 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) > > - > > -$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif5-tx.pcap | > > -trim_zeros > 5.packets > > -# Skipping the UDP checksum > > -cat 5.expected | cut -c 1-120,125- > expout > > -AT_CHECK([cat 5.packets | cut -c 1-120,125- ], [0], [expout]) > > +test_dhcpv6 5 $src_mac $src_lla 11 1 "" "" 5 > > +check_packets 5 > > > > ovn-nbctl --all destroy dhcp-option > > d1="$(ovn-nbctl create DHCP_Options cidr="ae70\:\:/64")" > > @@ -7494,26 +7517,22 @@ src_lla="fe80::f200:00ff:fe00:0002" > > offer_ip="ae70::5" > > > > test_dhcpv6 2 $src_mac $src_lla 1 $offer_ip "bootfile_name_alt" "" > > -# NXT_RESUMEs should be 5. > > -OVS_WAIT_UNTIL([test 5 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) > > +check_packets 2 > > > > -# vif2-tx.pcap should not have received the DHCPv6 reply packet > > -rm 2.packets > > -$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap | > trim_zeros > 2.packets > > -# Skipping the UDP checksum > > -cat 2.expected | cut -c 1-120,125- > expout > > -AT_CHECK([cat 2.packets | cut -c 1-120,125- ], [0], [expout]) > > +reset_pcap_file hv1-vif2 hv1/vif2 > > + > > +test_dhcpv6_release 2 $src_mac $src_lla $offer_ip > > +check_packets 2 > > > > reset_pcap_file hv1-vif2 hv1/vif2 > > -rm 2.packets 2.expected > > > > test_dhcpv6 2 $src_mac $src_lla 1 $offer_ip "bootfile_name" "" > > -# NXT_RESUMEs should be 6. > > -OVS_WAIT_UNTIL([test 6 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) > > +check_packets 2 > > + > > +reset_pcap_file hv1-vif2 hv1/vif2 > > > > -$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap | > trim_zeros > 2.packets > > -cat 2.expected | cut -c 1-120,125- > expout > > -AT_CHECK([cat 2.packets | cut -c 1-120,125- ], [0], [expout]) > > +test_dhcpv6_release 2 $src_mac $src_lla $offer_ip > > +check_packets 2 > > > > ovn-nbctl --all destroy dhcp-option > > d1="$(ovn-nbctl create DHCP_Options cidr="ae70\:\:/64")" > > @@ -7523,15 +7542,14 @@ ovn-nbctl dhcp-options-set-options $d1 \ > > ovn-nbctl --wait=hv lsp-set-dhcpv6-options ls1-lp2 ${d1} > > > > reset_pcap_file hv1-vif2 hv1/vif2 > > -rm 2.packets 2.expected > > > > test_dhcpv6 2 $src_mac $src_lla 1 $offer_ip "" "ovn.org" > > -# NXT_RESUMEs should be 7. > > -OVS_WAIT_UNTIL([test 7 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) > > +check_packets 2 > > + > > +reset_pcap_file hv1-vif2 hv1/vif2 > > > > -$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap | > trim_zeros > 2.packets > > -cat 2.expected | cut -c 1-120,125- > expout > > -AT_CHECK([cat 2.packets | cut -c 1-120,125- ], [0], [expout]) > > +test_dhcpv6_release 2 $src_mac $src_lla $offer_ip > > +check_packets 2 > > > > OVN_CLEANUP([hv1]) > > > > -- > > 2.41.0 > > > > _______________________________________________ > > dev mailing list > > [email protected] > > https://mail.openvswitch.org/mailman/listinfo/ovs-dev > > > > -- Ales Musil Senior Software Engineer - OVN Core Red Hat EMEA <https://www.redhat.com> [email protected] IM: amusil <https://red.ht/sig> _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
