From 43694e2a8d950f62781ec6dc613b5dac32de35fd Mon Sep 17 00:00:00 2001 From: Jesse Gross Date: Fri, 14 May 2010 13:49:43 -0700 Subject: [PATCH] netdev: Add 'patch' userspace implementation. Add a netdev to talk to the 'patch' vport in the kenerl. Since there is currently a 'patch' implementation using the veth driver, this one is temporarily called 'patchnew'. --- lib/automake.mk | 1 + lib/netdev-patch.c | 223 ++++++++++++++++++++++++++++++++++++++++++ lib/netdev-provider.h | 1 + lib/netdev.c | 1 + lib/vlog-modules.def | 1 + 5 files changed, 227 insertions(+) create mode 100644 lib/netdev-patch.c diff --git a/lib/automake.mk b/lib/automake.mk index 3bb88641a..53a900696 100644 --- a/lib/automake.mk +++ b/lib/automake.mk @@ -65,6 +65,7 @@ lib_libopenvswitch_a_SOURCES = \ lib/mac-learning.h \ lib/netdev-gre.c \ lib/netdev-linux.c \ + lib/netdev-patch.c \ lib/netdev-provider.h \ lib/netdev-vport.c \ lib/netdev-vport.h \ diff --git a/lib/netdev-patch.c b/lib/netdev-patch.c new file mode 100644 index 000000000..21a03636b --- /dev/null +++ b/lib/netdev-patch.c @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2010 Nicira Networks. + * + * 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 apatched 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. + */ + +#include +#include +#include +#include +#include + +#include "netdev-provider.h" +#include "netdev-vport.h" +#include "openflow/openflow.h" +#include "openvswitch/datapath-protocol.h" +#include "packets.h" +#include "socket-util.h" + +#define THIS_MODULE VLM_netdev_patch +#include "vlog.h" + +struct netdev_dev_patch { + struct netdev_dev netdev_dev; +}; + +struct netdev_patch { + struct netdev netdev; +}; + +static struct netdev_dev_patch * +netdev_dev_patch_cast(const struct netdev_dev *netdev_dev) +{ + netdev_dev_assert_class(netdev_dev, &netdev_patchnew_class); + return CONTAINER_OF(netdev_dev, struct netdev_dev_patch, netdev_dev); +} + +static struct netdev_patch * +netdev_patch_cast(const struct netdev *netdev) +{ + netdev_assert_class(netdev, &netdev_patchnew_class); + return CONTAINER_OF(netdev, struct netdev_patch, netdev); +} + +static int +parse_config(const char *name, const struct shash *args, + const char **peerp) +{ + const char *peer; + + peer = shash_find_data(args, "peer"); + if (!peer) { + VLOG_WARN("%s: patch type requires valid 'peer' argument", name); + return EINVAL; + } + + if (shash_count(args) > 1) { + VLOG_WARN("%s: patch type takes only a 'peer' argument", name); + return EINVAL; + } + + if (strlen(peer) >= IFNAMSIZ) { + VLOG_WARN("%s: patch 'peer' arg too long", name); + return EINVAL; + } + + if (!strcmp(name, peer)) { + VLOG_WARN("%s: patch peer must not be self", name); + return EINVAL; + } + + *peerp = peer; + + return 0; +} + +static int +netdev_patch_create(const char *name, const char *type OVS_UNUSED, + const struct shash *args, struct netdev_dev **netdev_devp) +{ + int err; + struct odp_vport_add ova; + const char *peer; + struct netdev_dev_patch *netdev_dev; + + err = parse_config(name, args, &peer); + if (err) { + return err; + } + + ovs_strlcpy(ova.port_type, "patch", sizeof ova.port_type); + ovs_strlcpy(ova.devname, name, sizeof ova.devname); + ova.config = (char *)peer; + + err = netdev_vport_do_ioctl(ODP_VPORT_ADD, &ova); + if (err == EEXIST) { + VLOG_WARN("%s: destroying existing device", name); + + err = netdev_vport_do_ioctl(ODP_VPORT_DEL, ova.devname); + if (err) { + return err; + } + + err = netdev_vport_do_ioctl(ODP_VPORT_ADD, &ova); + } + + if (err) { + return err; + } + + netdev_dev = xmalloc(sizeof *netdev_dev); + netdev_dev_init(&netdev_dev->netdev_dev, name, &netdev_patchnew_class); + + *netdev_devp = &netdev_dev->netdev_dev; + return 0; +} + +static int +netdev_patch_reconfigure(struct netdev_dev *netdev_dev_, const struct shash *args) +{ + const char *name = netdev_dev_get_name(netdev_dev_); + struct odp_vport_mod ovm; + const char *peer; + int err; + + err = parse_config(name, args, &peer); + if (err) { + return err; + } + + ovs_strlcpy(ovm.devname, name, sizeof ovm.devname); + ovm.config = (char *)peer; + + return netdev_vport_do_ioctl(ODP_VPORT_MOD, &ovm); +} + +static void +netdev_patch_destroy(struct netdev_dev *netdev_dev_) +{ + struct netdev_dev_patch *netdev_dev = netdev_dev_patch_cast(netdev_dev_); + + netdev_vport_do_ioctl(ODP_VPORT_DEL, (char *)netdev_dev_get_name(netdev_dev_)); + free(netdev_dev); +} + +static int +netdev_patch_open(struct netdev_dev *netdev_dev_, int ethertype OVS_UNUSED, + struct netdev **netdevp) +{ + struct netdev_patch *netdev; + + netdev = xmalloc(sizeof *netdev); + netdev_init(&netdev->netdev, netdev_dev_); + + *netdevp = &netdev->netdev; + return 0; +} + +static void +netdev_patch_close(struct netdev *netdev_) +{ + struct netdev_patch *netdev = netdev_patch_cast(netdev_); + free(netdev); +} + +const struct netdev_class netdev_patchnew_class = { + "patchnew", + + NULL, /* init */ + NULL, /* run */ + NULL, /* wait */ + + netdev_patch_create, + netdev_patch_destroy, + netdev_patch_reconfigure, + + netdev_patch_open, + netdev_patch_close, + + NULL, /* enumerate */ + + NULL, /* recv */ + NULL, /* recv_wait */ + NULL, /* drain */ + + NULL, /* send */ + NULL, /* send_wait */ + + netdev_vport_set_etheraddr, + netdev_vport_get_etheraddr, + netdev_vport_get_mtu, + NULL, /* get_ifindex */ + netdev_vport_get_carrier, + netdev_vport_get_stats, + NULL, /* set_stats */ + + NULL, /* get_features */ + NULL, /* set_advertisements */ + NULL, /* get_vlan_vid */ + NULL, /* set_policing */ + + NULL, /* get_in4 */ + NULL, /* set_in4 */ + NULL, /* get_in6 */ + NULL, /* add_router */ + NULL, /* get_next_hop */ + NULL, /* arp_lookup */ + + netdev_vport_update_flags, + + netdev_vport_poll_add, + netdev_vport_poll_remove, +}; diff --git a/lib/netdev-provider.h b/lib/netdev-provider.h index eb62cc18b..dcaaa869e 100644 --- a/lib/netdev-provider.h +++ b/lib/netdev-provider.h @@ -401,6 +401,7 @@ extern const struct netdev_class netdev_linux_class; extern const struct netdev_class netdev_tap_class; extern const struct netdev_class netdev_gre_class; extern const struct netdev_class netdev_patch_class; +extern const struct netdev_class netdev_patchnew_class; #ifdef __cplusplus } diff --git a/lib/netdev.c b/lib/netdev.c index 09c00af3f..c2049bf3c 100644 --- a/lib/netdev.c +++ b/lib/netdev.c @@ -46,6 +46,7 @@ static const struct netdev_class *base_netdev_classes[] = { &netdev_tap_class, &netdev_gre_class, &netdev_patch_class, + &netdev_patchnew_class, }; static struct shash netdev_classes = SHASH_INITIALIZER(&netdev_classes); diff --git a/lib/vlog-modules.def b/lib/vlog-modules.def index e03fc7223..7df87e6fd 100644 --- a/lib/vlog-modules.def +++ b/lib/vlog-modules.def @@ -45,6 +45,7 @@ VLOG_MODULE(mac_learning) VLOG_MODULE(netdev) VLOG_MODULE(netdev_gre) VLOG_MODULE(netdev_linux) +VLOG_MODULE(netdev_patch) VLOG_MODULE(netdev_vport) VLOG_MODULE(netflow) VLOG_MODULE(netlink) -- 2.43.0