Skip to content

Commit

Permalink
Merge pull request containers#18002 from Luap99/netavark-plugin
Browse files Browse the repository at this point in the history
add netavark plugin support
  • Loading branch information
openshift-merge-robot authored Apr 11, 2023
2 parents cf3374e + af7c258 commit 3a47342
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 99 deletions.
1 change: 1 addition & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
- Defaults for the `--cgroup-config` option for `podman create` and `podman run` can now be set in `containers.conf`.
- Podman now supports auto updates for containers running inside a pod ([#17181](https://github.com/containers/podman/issues/17181)).
- Podman can now use a SQLite database as a backend for increased stability. The default remains the old database, BoltDB. The database to use is selected through the `database_backend` field in `containers.conf`.
- Netavark plugin support is added, the netavark network backend now allows users to create custom network drivers. `podman network create -d <plugin>` can be used to create a network config for your plugin and then podman will use it like any other config and takes care of setup/teardown on container start/stop. This requires at least netavark version 1.6.

### Changes
- Remote builds using the `podman build` command no longer allows `.containerignore` or `.dockerignore` files to be symlinks outside the build context.
Expand Down
5 changes: 5 additions & 0 deletions cmd/podman/networks/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ func networkCreateFlags(cmd *cobra.Command) {
flags.StringArrayVar(&networkCreateOptions.Subnets, subnetFlagName, nil, "subnets in CIDR format")
_ = cmd.RegisterFlagCompletionFunc(subnetFlagName, completion.AutocompleteNone)

interfaceFlagName := "interface-name"
flags.StringVar(&networkCreateOptions.InterfaceName, interfaceFlagName, "", "interface name which is used by the driver")
_ = cmd.RegisterFlagCompletionFunc(interfaceFlagName, completion.AutocompleteNone)

flags.BoolVar(&networkCreateOptions.DisableDNS, "disable-dns", false, "disable dns plugin")

flags.BoolVar(&networkCreateOptions.IgnoreIfExists, "ignore", false, "Don't fail if network already exists")
Expand Down Expand Up @@ -118,6 +122,7 @@ func networkCreate(cmd *cobra.Command, args []string) error {
DNSEnabled: !networkCreateOptions.DisableDNS,
NetworkDNSServers: networkCreateOptions.NetworkDNSServers,
Internal: networkCreateOptions.Internal,
NetworkInterface: networkCreateOptions.InterfaceName,
}

if cmd.Flags().Changed(ipamDriverFlagName) {
Expand Down
36 changes: 24 additions & 12 deletions docs/source/markdown/podman-network-create.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ podman\-network-create - Create a Podman network

## DESCRIPTION
Create a network configuration for use with Podman. By default, Podman creates a bridge connection.
A *Macvlan* connection can be created with the *-d macvlan* option. A parent device for macvlan can
be designated with the *-o parent=`<device>`* option.
A *Macvlan* connection can be created with the *-d macvlan* option. A parent device for macvlan or
ipvlan can be designated with the *-o parent=`<device>`* or *--network-interface=`<device>`* option.

If no options are provided, Podman will assign a free subnet and name for the network.

Expand All @@ -22,38 +22,50 @@ release because it is used as a special network mode in **podman run/create --ne
#### **--disable-dns**

Disables the DNS plugin for this network which if enabled, can perform container to container name
resolution.
resolution. It is only supported with the `bridge` driver, for other drivers it will be always disabled.

#### **--dns**=*ip*

Set network-scoped DNS resolver/nameserver for containers in this network. If not set, the host servers from `/etc/resolv.conf` will be used. It can be overwritten on the container level with the `podman run/create --dns` option. This option can be specified multiple times to set more than one IP.

#### **--driver**, **-d**
#### **--driver**, **-d**=*driver*

Driver to manage the network. Currently `bridge`, `macvlan` and `ipvlan` are supported. Defaults to `bridge`.
As rootless the `macvlan` and `ipvlan` driver have no access to the host network interfaces because rootless networking requires a separate network namespace.

Special considerations for the *netavark* backend:
The netavark backend allows the use of so called *netavark plugins*, see the
[plugin-API.md](https://github.com/containers/netavark/blob/main/plugin-API.md)
documentation in netavark. The binary must be placed in a specified directory
so podman can discover it, this list is set in `netavark_plugin_dirs` in
**[containers.conf(5)](https://github.com/containers/common/blob/main/docs/containers.conf.5.md)**
under the `[network]` section.

- The `macvlan` driver requires the `--subnet` option, DHCP is currently not supported.
- The `ipvlan` driver is not currently supported.
The name of the plugin can then be used as driver to create a network for your plugin.
The list of all supported drivers and plugins can be seen with `podman info --format {{.Plugins.Network}}`.

#### **--gateway**
#### **--gateway**=*ip*

Define a gateway for the subnet. To provide a gateway address, a
*subnet* option is required. Can be specified multiple times.
The argument order of the **--subnet**, **--gateway** and **--ip-range** options must match.

#### **--ignore**

Ignore the create request if a network with the same name already exists instead of failing.
Note, trying to create a network with an existing name and different parameters, will not change the configuration of the existing one

#### **--interface-name**=*name*

This option maps the the *network_interface* option in the network config, see **podman network inspect**.
Depending on the driver this can have different effects, for `bridge` it will be the bridge interface name.
For `macvlan` and `ipvlan` this will be the parent device on the host. It is the same as `--opt parent=...`.

#### **--internal**

Restrict external access of this network. Note when using this option, the dnsname plugin will be
automatically disabled.

#### **--ip-range**
#### **--ip-range**=*range*

Allocate container IP from a range. The range must be a complete subnet and in CIDR notation. The *ip-range* option
must be used with a *subnet* option. Can be specified multiple times.
Expand All @@ -76,7 +88,7 @@ View the driver in the **podman network inspect** output under the `ipam_options

Enable IPv6 (Dual Stack) networking. If not subnets are given it will allocate an ipv4 and an ipv6 subnet.

#### **--label**
#### **--label**=*label*

Set metadata for a network (e.g., --label mykey=value).

Expand All @@ -103,7 +115,7 @@ The `macvlan` and `ipvlan` driver support the following options:
- Supported values for `macvlan` are `bridge`, `private`, `vepa`, `passthru`. Defaults to `bridge`.
- Supported values for `ipvlan` are `l2`, `l3`, `l3s`. Defaults to `l2`.

#### **--subnet**
#### **--subnet**=*subnet*

The subnet in CIDR notation. Can be specified multiple times to allocate more than one subnet for this network.
The argument order of the **--subnet**, **--gateway** and **--ip-range** options must match.
Expand Down Expand Up @@ -154,7 +166,7 @@ newnet
```

## SEE ALSO
**[podman(1)](podman.1.md)**, **[podman-network(1)](podman-network.1.md)**, **[podman-network-inspect(1)](podman-network-inspect.1.md)**, **[podman-network-ls(1)](podman-network-ls.1.md)**
**[podman(1)](podman.1.md)**, **[podman-network(1)](podman-network.1.md)**, **[podman-network-inspect(1)](podman-network-inspect.1.md)**, **[podman-network-ls(1)](podman-network-ls.1.md)**, **[containers.conf(5)](https://github.com/containers/common/blob/main/docs/containers.conf.5.md)**

## HISTORY
August 2021, Updated with the new network format by Paul Holzinger <[email protected]>
Expand Down
2 changes: 2 additions & 0 deletions pkg/domain/entities/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ type NetworkCreateOptions struct {
Options map[string]string
// IgnoreIfExists if true, do not fail if the network already exists
IgnoreIfExists bool
// InterfaceName sets the NetworkInterface in the network config
InterfaceName string
}

// NetworkUpdateOptions describes options to update a network
Expand Down
27 changes: 27 additions & 0 deletions test/e2e/network_create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -481,4 +481,31 @@ var _ = Describe("Podman network create", func() {
Expect(nc).To(Exit(0))
Expect(nc.OutputToString()).To(Equal(name))
})

It("podman network create --interface-name", func() {
netName := "bridge-" + stringid.GenerateRandomID()
bridgeName := "mybridge" + stringid.GenerateRandomID()[:4]
nc := podmanTest.Podman([]string{"network", "create", "--interface-name", bridgeName, netName})
nc.WaitWithDefaultTimeout()
defer podmanTest.removeNetwork(netName)
Expect(nc).To(Exit(0))
Expect(nc.OutputToString()).To(Equal(netName))

session := podmanTest.Podman([]string{"network", "inspect", "--format", "{{.NetworkInterface}}", netName})
session.WaitWithDefaultTimeout()
Expect(session).To(Exit(0))
Expect(session.OutputToString()).To(Equal(bridgeName))

session = podmanTest.Podman([]string{"run", "-d", "--network", netName, ALPINE, "top"})
session.WaitWithDefaultTimeout()
Expect(session).To(Exit(0))

// can only check this as root
if !isRootless() {
// make sure cni/netavark created bridge with expected name
bridge, err := net.InterfaceByName(bridgeName)
Expect(err).ToNot(HaveOccurred())
Expect(bridge.Name).To(Equal(bridgeName))
}
})
})
113 changes: 32 additions & 81 deletions test/e2e/network_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -477,59 +477,7 @@ var _ = Describe("Podman network", func() {
Expect(lines[1]).To(Equal(netName2))
})

It("podman CNI network with multiple aliases", func() {
SkipIfNetavark(podmanTest)
var worked bool
netName := createNetworkName("aliasTest")
session := podmanTest.Podman([]string{"network", "create", netName})
session.WaitWithDefaultTimeout()
defer podmanTest.removeNetwork(netName)
Expect(session).Should(Exit(0))

interval := 250 * time.Millisecond
for i := 0; i < 6; i++ {
n := podmanTest.Podman([]string{"network", "exists", netName})
n.WaitWithDefaultTimeout()
worked = n.ExitCode() == 0
if worked {
break
}
time.Sleep(interval)
interval *= 2
}

top := podmanTest.Podman([]string{"run", "-dt", "--name=web", "--network=" + netName, "--network-alias=web1", "--network-alias=web2", NGINX_IMAGE})
top.WaitWithDefaultTimeout()
Expect(top).Should(Exit(0))
interval = 250 * time.Millisecond
// Wait for the nginx service to be running
for i := 0; i < 6; i++ {
// Test curl against the container's name
c1 := podmanTest.Podman([]string{"run", "--dns-search", "dns.podman", "--network=" + netName, NGINX_IMAGE, "curl", "web"})
c1.WaitWithDefaultTimeout()
worked = c1.ExitCode() == 0
if worked {
break
}
time.Sleep(interval)
interval *= 2
}
Expect(worked).To(BeTrue())

// Nginx is now running so no need to do a loop
// Test against the first alias
c2 := podmanTest.Podman([]string{"run", "--dns-search", "dns.podman", "--network=" + netName, NGINX_IMAGE, "curl", "web1"})
c2.WaitWithDefaultTimeout()
Expect(c2).Should(Exit(0))

// Test against the second alias
c3 := podmanTest.Podman([]string{"run", "--dns-search", "dns.podman", "--network=" + netName, NGINX_IMAGE, "curl", "web2"})
c3.WaitWithDefaultTimeout()
Expect(c3).Should(Exit(0))
})

It("podman Netavark network with multiple aliases", func() {
SkipIfCNI(podmanTest)
It("podman network with multiple aliases", func() {
var worked bool
netName := createNetworkName("aliasTest")
session := podmanTest.Podman([]string{"network", "create", netName})
Expand Down Expand Up @@ -620,34 +568,37 @@ var _ = Describe("Podman network", func() {
Expect(nc).Should(Exit(0))
})

It("podman network create/remove macvlan as driver (-d) with device name", func() {
// Netavark currently does not do dhcp so the this test fails
SkipIfNetavark(podmanTest)
net := "macvlan" + stringid.GenerateRandomID()
nc := podmanTest.Podman([]string{"network", "create", "-d", "macvlan", "-o", "parent=lo", net})
nc.WaitWithDefaultTimeout()
defer podmanTest.removeNetwork(net)
Expect(nc).Should(Exit(0))

inspect := podmanTest.Podman([]string{"network", "inspect", net})
inspect.WaitWithDefaultTimeout()
Expect(inspect).Should(Exit(0))

var results []types.Network
err := json.Unmarshal([]byte(inspect.OutputToString()), &results)
Expect(err).ToNot(HaveOccurred())
Expect(results).To(HaveLen(1))
result := results[0]

Expect(result).To(HaveField("Driver", "macvlan"))
Expect(result).To(HaveField("NetworkInterface", "lo"))
Expect(result.IPAMOptions).To(HaveKeyWithValue("driver", "dhcp"))
Expect(result.Subnets).To(HaveLen(0))

nc = podmanTest.Podman([]string{"network", "rm", net})
nc.WaitWithDefaultTimeout()
Expect(nc).Should(Exit(0))
})
for _, opt := range []string{"-o=parent=lo", "--interface-name=lo"} {
opt := opt
It(fmt.Sprintf("podman network create/remove macvlan as driver (-d) with %s", opt), func() {
// Netavark currently does not do dhcp so the this test fails
SkipIfNetavark(podmanTest)
net := "macvlan" + stringid.GenerateRandomID()
nc := podmanTest.Podman([]string{"network", "create", "-d", "macvlan", opt, net})
nc.WaitWithDefaultTimeout()
defer podmanTest.removeNetwork(net)
Expect(nc).Should(Exit(0))

inspect := podmanTest.Podman([]string{"network", "inspect", net})
inspect.WaitWithDefaultTimeout()
Expect(inspect).Should(Exit(0))

var results []types.Network
err := json.Unmarshal([]byte(inspect.OutputToString()), &results)
Expect(err).ToNot(HaveOccurred())
Expect(results).To(HaveLen(1))
result := results[0]

Expect(result).To(HaveField("Driver", "macvlan"))
Expect(result).To(HaveField("NetworkInterface", "lo"))
Expect(result.IPAMOptions).To(HaveKeyWithValue("driver", "dhcp"))
Expect(result.Subnets).To(HaveLen(0))

nc = podmanTest.Podman([]string{"network", "rm", net})
nc.WaitWithDefaultTimeout()
Expect(nc).Should(Exit(0))
})
}

It("podman network create/remove ipvlan as driver (-d) with device name", func() {
// Netavark currently does not support ipvlan
Expand Down
9 changes: 3 additions & 6 deletions test/e2e/run_networking_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -961,8 +961,7 @@ EXPOSE 2004-2005/tcp`, ALPINE)
Expect(run.OutputToString()).To(ContainSubstring(ipAddr))
})

It("podman CNI network works across user ns", func() {
SkipIfNetavark(podmanTest)
It("podman network works across user ns", func() {
netName := stringid.GenerateRandomID()
create := podmanTest.Podman([]string{"network", "create", netName})
create.WaitWithDefaultTimeout()
Expand Down Expand Up @@ -1085,8 +1084,7 @@ EXPOSE 2004-2005/tcp`, ALPINE)
pingTest("--net=private")
})

It("podman run check dnsname plugin with CNI", func() {
SkipIfNetavark(podmanTest)
It("podman run check dns", func() {
pod := "testpod"
session := podmanTest.Podman([]string{"pod", "create", "--name", pod})
session.WaitWithDefaultTimeout()
Expand Down Expand Up @@ -1157,8 +1155,7 @@ EXPOSE 2004-2005/tcp`, ALPINE)
Expect(session).Should(Exit(0))
})

It("podman run check dnsname adds dns search domain with CNI", func() {
SkipIfNetavark(podmanTest)
It("podman network adds dns search domain with dns", func() {
net := createNetworkName("dnsname")
session := podmanTest.Podman([]string{"network", "create", net})
session.WaitWithDefaultTimeout()
Expand Down

0 comments on commit 3a47342

Please sign in to comment.