Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
L
lxc
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Chen Yisong
lxc
Commits
677c9967
Unverified
Commit
677c9967
authored
Jun 09, 2020
by
Christian Brauner
Committed by
GitHub
Jun 09, 2020
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #3439 from tomponline/tp-nic-veth-vlan-ovs
NIC: Veth OVS bridge VLAN support
parents
bdf46165
38790036
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
536 additions
and
3 deletions
+536
-3
lxc.container.conf.sgml.in
doc/lxc.container.conf.sgml.in
+6
-0
api_extensions.h
src/lxc/api_extensions.h
+1
-0
confile.c
src/lxc/confile.c
+156
-0
confile_utils.c
src/lxc/confile_utils.c
+15
-0
macro.h
src/lxc/macro.h
+31
-0
network.c
src/lxc/network.c
+309
-3
network.h
src/lxc/network.h
+3
-0
parse_config_file.c
src/tests/parse_config_file.c
+15
-0
No files found.
doc/lxc.container.conf.sgml.in
View file @
677c9967
...
@@ -474,6 +474,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
...
@@ -474,6 +474,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
<option>lxc.net.[i].veth.ipv6.route</option> options.
<option>lxc.net.[i].veth.ipv6.route</option> options.
Several lines specify several routes.
Several lines specify several routes.
The route is in format x.y.z.t/m, eg. 192.168.1.0/24.
The route is in format x.y.z.t/m, eg. 192.168.1.0/24.
In <option>bridge</option> mode untagged VLAN membership can be set with the
<option>lxc.net.[i].veth.vlan.id</option> option. It accepts a special value of 'none' indicating
that the container port should be removed from the bridge's default untagged VLAN.
The <option>lxc.net.[i].veth.vlan.tagged.id</option> option can be specified multiple times to set
the container's bridge port membership to one or more tagged VLANs.
</para>
</para>
<para>
<para>
...
...
src/lxc/api_extensions.h
View file @
677c9967
...
@@ -40,6 +40,7 @@ static char *api_extensions[] = {
...
@@ -40,6 +40,7 @@ static char *api_extensions[] = {
"cgroup2"
,
"cgroup2"
,
"pidfd"
,
"pidfd"
,
"cgroup_advanced_isolation"
,
"cgroup_advanced_isolation"
,
"network_bridge_vlan"
,
};
};
static
size_t
nr_api_extensions
=
sizeof
(
api_extensions
)
/
sizeof
(
*
api_extensions
);
static
size_t
nr_api_extensions
=
sizeof
(
api_extensions
)
/
sizeof
(
*
api_extensions
);
...
...
src/lxc/confile.c
View file @
677c9967
...
@@ -32,6 +32,7 @@
...
@@ -32,6 +32,7 @@
#include "../include/netns_ifaddrs.h"
#include "../include/netns_ifaddrs.h"
#include "log.h"
#include "log.h"
#include "lxcseccomp.h"
#include "lxcseccomp.h"
#include "macro.h"
#include "memory_utils.h"
#include "memory_utils.h"
#include "network.h"
#include "network.h"
#include "parse.h"
#include "parse.h"
...
@@ -126,6 +127,8 @@ lxc_config_define(net_veth_mode);
...
@@ -126,6 +127,8 @@ lxc_config_define(net_veth_mode);
lxc_config_define
(
net_veth_pair
);
lxc_config_define
(
net_veth_pair
);
lxc_config_define
(
net_veth_ipv4_route
);
lxc_config_define
(
net_veth_ipv4_route
);
lxc_config_define
(
net_veth_ipv6_route
);
lxc_config_define
(
net_veth_ipv6_route
);
lxc_config_define
(
net_veth_vlan_id
);
lxc_config_define
(
net_veth_vlan_tagged_id
);
lxc_config_define
(
net_vlan_id
);
lxc_config_define
(
net_vlan_id
);
lxc_config_define
(
no_new_privs
);
lxc_config_define
(
no_new_privs
);
lxc_config_define
(
personality
);
lxc_config_define
(
personality
);
...
@@ -239,6 +242,8 @@ static struct lxc_config_t config_jump_table[] = {
...
@@ -239,6 +242,8 @@ static struct lxc_config_t config_jump_table[] = {
{
"lxc.net.veth.pair"
,
set_config_net_veth_pair
,
get_config_net_veth_pair
,
clr_config_net_veth_pair
,
},
{
"lxc.net.veth.pair"
,
set_config_net_veth_pair
,
get_config_net_veth_pair
,
clr_config_net_veth_pair
,
},
{
"lxc.net.veth.ipv4.route"
,
set_config_net_veth_ipv4_route
,
get_config_net_veth_ipv4_route
,
clr_config_net_veth_ipv4_route
,
},
{
"lxc.net.veth.ipv4.route"
,
set_config_net_veth_ipv4_route
,
get_config_net_veth_ipv4_route
,
clr_config_net_veth_ipv4_route
,
},
{
"lxc.net.veth.ipv6.route"
,
set_config_net_veth_ipv6_route
,
get_config_net_veth_ipv6_route
,
clr_config_net_veth_ipv6_route
,
},
{
"lxc.net.veth.ipv6.route"
,
set_config_net_veth_ipv6_route
,
get_config_net_veth_ipv6_route
,
clr_config_net_veth_ipv6_route
,
},
{
"lxc.net.veth.vlan.id"
,
set_config_net_veth_vlan_id
,
get_config_net_veth_vlan_id
,
clr_config_net_veth_vlan_id
,
},
{
"lxc.net.veth.vlan.tagged.id"
,
set_config_net_veth_vlan_tagged_id
,
get_config_net_veth_vlan_tagged_id
,
clr_config_net_veth_vlan_tagged_id
,
},
{
"lxc.net."
,
set_config_net_nic
,
get_config_net_nic
,
clr_config_net_nic
,
},
{
"lxc.net."
,
set_config_net_nic
,
get_config_net_nic
,
clr_config_net_nic
,
},
{
"lxc.net"
,
set_config_net
,
get_config_net
,
clr_config_net
,
},
{
"lxc.net"
,
set_config_net
,
get_config_net
,
clr_config_net
,
},
{
"lxc.no_new_privs"
,
set_config_no_new_privs
,
get_config_no_new_privs
,
clr_config_no_new_privs
,
},
{
"lxc.no_new_privs"
,
set_config_no_new_privs
,
get_config_no_new_privs
,
clr_config_no_new_privs
,
},
...
@@ -306,6 +311,7 @@ static int set_config_net_type(const char *key, const char *value,
...
@@ -306,6 +311,7 @@ static int set_config_net_type(const char *key, const char *value,
netdev
->
type
=
LXC_NET_VETH
;
netdev
->
type
=
LXC_NET_VETH
;
lxc_list_init
(
&
netdev
->
priv
.
veth_attr
.
ipv4_routes
);
lxc_list_init
(
&
netdev
->
priv
.
veth_attr
.
ipv4_routes
);
lxc_list_init
(
&
netdev
->
priv
.
veth_attr
.
ipv6_routes
);
lxc_list_init
(
&
netdev
->
priv
.
veth_attr
.
ipv6_routes
);
lxc_list_init
(
&
netdev
->
priv
.
veth_attr
.
vlan_tagged_ids
);
if
(
!
lxc_veth_flag_to_mode
(
netdev
->
priv
.
veth_attr
.
mode
))
if
(
!
lxc_veth_flag_to_mode
(
netdev
->
priv
.
veth_attr
.
mode
))
lxc_veth_mode_to_flag
(
&
netdev
->
priv
.
veth_attr
.
mode
,
"bridge"
);
lxc_veth_mode_to_flag
(
&
netdev
->
priv
.
veth_attr
.
mode
,
"bridge"
);
}
else
if
(
strcmp
(
value
,
"macvlan"
)
==
0
)
{
}
else
if
(
strcmp
(
value
,
"macvlan"
)
==
0
)
{
...
@@ -487,6 +493,69 @@ static int set_config_net_veth_pair(const char *key, const char *value,
...
@@ -487,6 +493,69 @@ static int set_config_net_veth_pair(const char *key, const char *value,
return
network_ifname
(
netdev
->
priv
.
veth_attr
.
pair
,
value
,
sizeof
(
netdev
->
priv
.
veth_attr
.
pair
));
return
network_ifname
(
netdev
->
priv
.
veth_attr
.
pair
,
value
,
sizeof
(
netdev
->
priv
.
veth_attr
.
pair
));
}
}
static
int
set_config_net_veth_vlan_id
(
const
char
*
key
,
const
char
*
value
,
struct
lxc_conf
*
lxc_conf
,
void
*
data
)
{
int
ret
;
struct
lxc_netdev
*
netdev
=
data
;
if
(
!
netdev
)
return
ret_errno
(
EINVAL
);
if
(
lxc_config_value_empty
(
value
))
return
clr_config_net_veth_vlan_id
(
key
,
lxc_conf
,
data
);
if
(
strcmp
(
value
,
"none"
)
==
0
)
{
netdev
->
priv
.
veth_attr
.
vlan_id
=
BRIDGE_VLAN_NONE
;
}
else
{
unsigned
short
vlan_id
;
ret
=
get_u16
(
&
vlan_id
,
value
,
0
);
if
(
ret
<
0
)
return
ret_errno
(
EINVAL
);
if
(
vlan_id
>
BRIDGE_VLAN_ID_MAX
)
return
ret_errno
(
EINVAL
);
netdev
->
priv
.
veth_attr
.
vlan_id
=
vlan_id
;
}
netdev
->
priv
.
veth_attr
.
vlan_id_set
=
true
;
return
0
;
}
static
int
set_config_net_veth_vlan_tagged_id
(
const
char
*
key
,
const
char
*
value
,
struct
lxc_conf
*
lxc_conf
,
void
*
data
)
{
__do_free
struct
lxc_list
*
list
=
NULL
;
int
ret
;
unsigned
short
vlan_id
;
struct
lxc_netdev
*
netdev
=
data
;
if
(
!
netdev
)
return
ret_errno
(
EINVAL
);
if
(
lxc_config_value_empty
(
value
))
return
clr_config_net_veth_vlan_tagged_id
(
key
,
lxc_conf
,
data
);
ret
=
get_u16
(
&
vlan_id
,
value
,
0
);
if
(
ret
<
0
)
ret_errno
(
EINVAL
);
if
(
vlan_id
>
BRIDGE_VLAN_ID_MAX
)
ret_errno
(
EINVAL
);
list
=
malloc
(
sizeof
(
*
list
));
if
(
!
list
)
return
ret_errno
(
ENOMEM
);
lxc_list_init
(
list
);
list
->
elem
=
UINT_TO_PTR
(
vlan_id
);
lxc_list_add_tail
(
&
netdev
->
priv
.
veth_attr
.
vlan_tagged_ids
,
move_ptr
(
list
));
return
0
;
}
static
int
set_config_net_macvlan_mode
(
const
char
*
key
,
const
char
*
value
,
static
int
set_config_net_macvlan_mode
(
const
char
*
key
,
const
char
*
value
,
struct
lxc_conf
*
lxc_conf
,
void
*
data
)
struct
lxc_conf
*
lxc_conf
,
void
*
data
)
{
{
...
@@ -5301,6 +5370,38 @@ static int clr_config_net_veth_pair(const char *key, struct lxc_conf *lxc_conf,
...
@@ -5301,6 +5370,38 @@ static int clr_config_net_veth_pair(const char *key, struct lxc_conf *lxc_conf,
return
0
;
return
0
;
}
}
static
int
clr_config_net_veth_vlan_id
(
const
char
*
key
,
struct
lxc_conf
*
lxc_conf
,
void
*
data
)
{
struct
lxc_netdev
*
netdev
=
data
;
if
(
!
netdev
)
return
ret_errno
(
EINVAL
);
netdev
->
priv
.
veth_attr
.
vlan_id
=
0
;
netdev
->
priv
.
veth_attr
.
vlan_id_set
=
false
;
return
0
;
}
static
int
clr_config_net_veth_vlan_tagged_id
(
const
char
*
key
,
struct
lxc_conf
*
lxc_conf
,
void
*
data
)
{
struct
lxc_netdev
*
netdev
=
data
;
struct
lxc_list
*
cur
,
*
next
;
if
(
!
netdev
)
return
ret_errno
(
EINVAL
);
lxc_list_for_each_safe
(
cur
,
&
netdev
->
priv
.
veth_attr
.
vlan_tagged_ids
,
next
)
{
lxc_list_del
(
cur
);
free
(
cur
);
}
return
0
;
}
static
int
clr_config_net_script_up
(
const
char
*
key
,
struct
lxc_conf
*
lxc_conf
,
static
int
clr_config_net_script_up
(
const
char
*
key
,
struct
lxc_conf
*
lxc_conf
,
void
*
data
)
void
*
data
)
{
{
...
@@ -5772,6 +5873,60 @@ static int get_config_net_veth_pair(const char *key, char *retv, int inlen,
...
@@ -5772,6 +5873,60 @@ static int get_config_net_veth_pair(const char *key, char *retv, int inlen,
return
fulllen
;
return
fulllen
;
}
}
static
int
get_config_net_veth_vlan_id
(
const
char
*
key
,
char
*
retv
,
int
inlen
,
struct
lxc_conf
*
c
,
void
*
data
)
{
int
len
;
int
fulllen
=
0
;
struct
lxc_netdev
*
netdev
=
data
;
if
(
!
netdev
)
return
ret_errno
(
EINVAL
);
if
(
netdev
->
type
!=
LXC_NET_VETH
)
return
0
;
if
(
!
retv
)
inlen
=
0
;
else
memset
(
retv
,
0
,
inlen
);
strprint
(
retv
,
inlen
,
"%d"
,
netdev
->
priv
.
veth_attr
.
vlan_id
);
return
fulllen
;
}
static
int
get_config_net_veth_vlan_tagged_id
(
const
char
*
key
,
char
*
retv
,
int
inlen
,
struct
lxc_conf
*
c
,
void
*
data
)
{
int
len
;
size_t
listlen
;
struct
lxc_list
*
it
;
int
fulllen
=
0
;
struct
lxc_netdev
*
netdev
=
data
;
if
(
!
netdev
)
ret_errno
(
EINVAL
);
if
(
netdev
->
type
!=
LXC_NET_VETH
)
return
0
;
if
(
!
retv
)
inlen
=
0
;
else
memset
(
retv
,
0
,
inlen
);
listlen
=
lxc_list_len
(
&
netdev
->
priv
.
veth_attr
.
vlan_tagged_ids
);
lxc_list_for_each
(
it
,
&
netdev
->
priv
.
veth_attr
.
vlan_tagged_ids
)
{
unsigned
short
i
=
PTR_TO_USHORT
(
it
->
elem
);
strprint
(
retv
,
inlen
,
"%u%s"
,
i
,
(
listlen
--
>
1
)
?
"
\n
"
:
""
);
}
return
fulllen
;
}
static
int
get_config_net_script_up
(
const
char
*
key
,
char
*
retv
,
int
inlen
,
static
int
get_config_net_script_up
(
const
char
*
key
,
char
*
retv
,
int
inlen
,
struct
lxc_conf
*
c
,
void
*
data
)
struct
lxc_conf
*
c
,
void
*
data
)
{
{
...
@@ -6200,6 +6355,7 @@ int lxc_list_net(struct lxc_conf *c, const char *key, char *retv, int inlen)
...
@@ -6200,6 +6355,7 @@ int lxc_list_net(struct lxc_conf *c, const char *key, char *retv, int inlen)
strprint
(
retv
,
inlen
,
"veth.pair
\n
"
);
strprint
(
retv
,
inlen
,
"veth.pair
\n
"
);
strprint
(
retv
,
inlen
,
"veth.ipv4.route
\n
"
);
strprint
(
retv
,
inlen
,
"veth.ipv4.route
\n
"
);
strprint
(
retv
,
inlen
,
"veth.ipv6.route
\n
"
);
strprint
(
retv
,
inlen
,
"veth.ipv6.route
\n
"
);
strprint
(
retv
,
inlen
,
"veth.vlan.id
\n
"
);
break
;
break
;
case
LXC_NET_MACVLAN
:
case
LXC_NET_MACVLAN
:
strprint
(
retv
,
inlen
,
"macvlan.mode
\n
"
);
strprint
(
retv
,
inlen
,
"macvlan.mode
\n
"
);
...
...
src/lxc/confile_utils.c
View file @
677c9967
...
@@ -257,6 +257,7 @@ void lxc_log_configured_netdevs(const struct lxc_conf *conf)
...
@@ -257,6 +257,7 @@ void lxc_log_configured_netdevs(const struct lxc_conf *conf)
switch
(
netdev
->
type
)
{
switch
(
netdev
->
type
)
{
case
LXC_NET_VETH
:
case
LXC_NET_VETH
:
TRACE
(
"type: veth"
);
TRACE
(
"type: veth"
);
TRACE
(
"veth mode: %d"
,
netdev
->
priv
.
veth_attr
.
mode
);
if
(
netdev
->
priv
.
veth_attr
.
pair
[
0
]
!=
'\0'
)
if
(
netdev
->
priv
.
veth_attr
.
pair
[
0
]
!=
'\0'
)
TRACE
(
"veth pair: %s"
,
TRACE
(
"veth pair: %s"
,
...
@@ -269,6 +270,15 @@ void lxc_log_configured_netdevs(const struct lxc_conf *conf)
...
@@ -269,6 +270,15 @@ void lxc_log_configured_netdevs(const struct lxc_conf *conf)
if
(
netdev
->
priv
.
veth_attr
.
ifindex
>
0
)
if
(
netdev
->
priv
.
veth_attr
.
ifindex
>
0
)
TRACE
(
"host side ifindex for veth device: %d"
,
TRACE
(
"host side ifindex for veth device: %d"
,
netdev
->
priv
.
veth_attr
.
ifindex
);
netdev
->
priv
.
veth_attr
.
ifindex
);
if
(
netdev
->
priv
.
veth_attr
.
vlan_id_set
)
TRACE
(
"veth vlan id: %d"
,
netdev
->
priv
.
veth_attr
.
vlan_id
);
lxc_list_for_each_safe
(
cur
,
&
netdev
->
priv
.
veth_attr
.
vlan_tagged_ids
,
next
)
{
unsigned
short
vlan_tagged_id
=
PTR_TO_USHORT
(
cur
->
elem
);
TRACE
(
"veth vlan tagged id: %u"
,
vlan_tagged_id
);
}
break
;
break
;
case
LXC_NET_MACVLAN
:
case
LXC_NET_MACVLAN
:
TRACE
(
"type: macvlan"
);
TRACE
(
"type: macvlan"
);
...
@@ -439,6 +449,11 @@ static void lxc_free_netdev(struct lxc_netdev *netdev)
...
@@ -439,6 +449,11 @@ static void lxc_free_netdev(struct lxc_netdev *netdev)
free
(
cur
->
elem
);
free
(
cur
->
elem
);
free
(
cur
);
free
(
cur
);
}
}
lxc_list_for_each_safe
(
cur
,
&
netdev
->
priv
.
veth_attr
.
vlan_tagged_ids
,
next
)
{
lxc_list_del
(
cur
);
free
(
cur
);
}
}
}
free
(
netdev
);
free
(
netdev
);
...
...
src/lxc/macro.h
View file @
677c9967
...
@@ -380,6 +380,34 @@ extern int __build_bug_on_failed;
...
@@ -380,6 +380,34 @@ extern int __build_bug_on_failed;
#define IPVLAN_ISOLATION_VEPA 2
#define IPVLAN_ISOLATION_VEPA 2
#endif
#endif
#ifndef BRIDGE_VLAN_NONE
#define BRIDGE_VLAN_NONE -1
/* Bridge VLAN option set to "none". */
#endif
#ifndef BRIDGE_VLAN_ID_MAX
#define BRIDGE_VLAN_ID_MAX 4094
/* Bridge VLAN MAX VLAN ID. */
#endif
#ifndef BRIDGE_FLAGS_MASTER
#define BRIDGE_FLAGS_MASTER 1
/* Bridge command to/from master */
#endif
#ifndef BRIDGE_VLAN_INFO_PVID
#define BRIDGE_VLAN_INFO_PVID (1<<1)
/* VLAN is PVID, ingress untagged */
#endif
#ifndef BRIDGE_VLAN_INFO_UNTAGGED
#define BRIDGE_VLAN_INFO_UNTAGGED (1<<2)
/* VLAN egresses untagged */
#endif
#ifndef IFLA_BRIDGE_FLAGS
#define IFLA_BRIDGE_FLAGS 0
#endif
#ifndef IFLA_BRIDGE_VLAN_INFO
#define IFLA_BRIDGE_VLAN_INFO 2
#endif
/* Attributes of RTM_NEWNSID/RTM_GETNSID messages */
/* Attributes of RTM_NEWNSID/RTM_GETNSID messages */
enum
{
enum
{
__LXC_NETNSA_NONE
,
__LXC_NETNSA_NONE
,
...
@@ -433,6 +461,9 @@ enum {
...
@@ -433,6 +461,9 @@ enum {
#define PTR_TO_UINT64(p) ((uint64_t)((intptr_t)(p)))
#define PTR_TO_UINT64(p) ((uint64_t)((intptr_t)(p)))
#define UINT_TO_PTR(u) ((void *) ((uintptr_t) (u)))
#define PTR_TO_USHORT(p) ((unsigned short)((uintptr_t)(p)))
#define LXC_INVALID_UID ((uid_t)-1)
#define LXC_INVALID_UID ((uid_t)-1)
#define LXC_INVALID_GID ((gid_t)-1)
#define LXC_INVALID_GID ((gid_t)-1)
...
...
src/lxc/network.c
View file @
677c9967
...
@@ -245,6 +245,289 @@ static int lxc_is_ip_forwarding_enabled(const char *ifname, int family)
...
@@ -245,6 +245,289 @@ static int lxc_is_ip_forwarding_enabled(const char *ifname, int family)
return
lxc_read_file_expect
(
path
,
buf
,
1
,
"1"
);
return
lxc_read_file_expect
(
path
,
buf
,
1
,
"1"
);
}
}
struct
bridge_vlan_info
{
__u16
flags
;
__u16
vid
;
};
static
int
lxc_bridge_vlan
(
unsigned
int
ifindex
,
unsigned
short
operation
,
unsigned
short
vlan_id
,
bool
tagged
)
{
call_cleaner
(
nlmsg_free
)
struct
nlmsg
*
answer
=
NULL
,
*
nlmsg
=
NULL
;
struct
nl_handler
nlh
;
call_cleaner
(
netlink_close
)
struct
nl_handler
*
nlh_ptr
=
&
nlh
;
int
err
;
struct
ifinfomsg
*
ifi
;
struct
rtattr
*
nest
;
unsigned
short
bridge_flags
=
0
;
struct
bridge_vlan_info
vlan_info
;
err
=
netlink_open
(
nlh_ptr
,
NETLINK_ROUTE
);
if
(
err
)
return
err
;
nlmsg
=
nlmsg_alloc
(
NLMSG_GOOD_SIZE
);
if
(
!
nlmsg
)
return
ret_errno
(
ENOMEM
);
answer
=
nlmsg_alloc_reserve
(
NLMSG_GOOD_SIZE
);
if
(
!
answer
)
return
ret_errno
(
ENOMEM
);
nlmsg
->
nlmsghdr
->
nlmsg_flags
=
NLM_F_REQUEST
|
NLM_F_ACK
;
nlmsg
->
nlmsghdr
->
nlmsg_type
=
operation
;
ifi
=
nlmsg_reserve
(
nlmsg
,
sizeof
(
struct
ifinfomsg
));
if
(
!
ifi
)
return
ret_errno
(
ENOMEM
);
ifi
->
ifi_family
=
AF_BRIDGE
;
ifi
->
ifi_index
=
ifindex
;
nest
=
nla_begin_nested
(
nlmsg
,
IFLA_AF_SPEC
);
if
(
!
nest
)
return
ret_errno
(
ENOMEM
);
bridge_flags
|=
BRIDGE_FLAGS_MASTER
;
if
(
nla_put_u16
(
nlmsg
,
IFLA_BRIDGE_FLAGS
,
bridge_flags
))
return
ret_errno
(
ENOMEM
);
vlan_info
.
vid
=
vlan_id
;
vlan_info
.
flags
=
0
;
if
(
!
tagged
)
vlan_info
.
flags
=
BRIDGE_VLAN_INFO_PVID
|
BRIDGE_VLAN_INFO_UNTAGGED
;
if
(
nla_put_buffer
(
nlmsg
,
IFLA_BRIDGE_VLAN_INFO
,
&
vlan_info
,
sizeof
(
struct
bridge_vlan_info
)))
return
ret_errno
(
ENOMEM
);
nla_end_nested
(
nlmsg
,
nest
);
return
netlink_transaction
(
nlh_ptr
,
nlmsg
,
answer
);
}
static
int
lxc_bridge_vlan_add
(
unsigned
int
ifindex
,
unsigned
short
vlan_id
,
bool
tagged
)
{
return
lxc_bridge_vlan
(
ifindex
,
RTM_SETLINK
,
vlan_id
,
tagged
);
}
static
int
lxc_bridge_vlan_del
(
unsigned
int
ifindex
,
unsigned
short
vlan_id
)
{
return
lxc_bridge_vlan
(
ifindex
,
RTM_DELLINK
,
vlan_id
,
false
);
}
static
int
lxc_bridge_vlan_add_tagged
(
unsigned
int
ifindex
,
struct
lxc_list
*
vlan_ids
)
{
struct
lxc_list
*
iterator
;
int
err
;
lxc_list_for_each
(
iterator
,
vlan_ids
)
{
unsigned
short
vlan_id
=
PTR_TO_USHORT
(
iterator
->
elem
);
err
=
lxc_bridge_vlan_add
(
ifindex
,
vlan_id
,
true
);
if
(
err
)
return
log_error_errno
(
-
1
,
-
err
,
"Failed to add tagged vlan
\"
%u
\"
to ifindex
\"
%d
\"
"
,
vlan_id
,
ifindex
);
}
return
0
;
}
static
int
validate_veth
(
struct
lxc_netdev
*
netdev
)
{
if
(
netdev
->
priv
.
veth_attr
.
mode
!=
VETH_MODE_BRIDGE
||
is_empty_string
(
netdev
->
link
))
{
/* Check that veth.vlan.id isn't being used in non bridge veth.mode. */
if
(
netdev
->
priv
.
veth_attr
.
vlan_id_set
)
return
log_error_errno
(
-
1
,
EINVAL
,
"Cannot use veth vlan.id when not in bridge mode or no bridge link specified"
);
/* Check that veth.vlan.tagged.id isn't being used in non bridge veth.mode. */
if
(
lxc_list_len
(
&
netdev
->
priv
.
veth_attr
.
vlan_tagged_ids
)
>
0
)
return
log_error_errno
(
-
1
,
EINVAL
,
"Cannot use veth vlan.id when not in bridge mode or no bridge link specified"
);
}
if
(
netdev
->
priv
.
veth_attr
.
vlan_id_set
)
{
struct
lxc_list
*
it
;
lxc_list_for_each
(
it
,
&
netdev
->
priv
.
veth_attr
.
vlan_tagged_ids
)
{
unsigned
short
i
=
PTR_TO_USHORT
(
it
->
elem
);
if
(
i
==
netdev
->
priv
.
veth_attr
.
vlan_id
)
return
log_error_errno
(
-
1
,
EINVAL
,
"Cannot use same veth vlan.id
\"
%u
\"
in vlan.tagged.id"
,
netdev
->
priv
.
veth_attr
.
vlan_id
);
}
}
return
0
;
}
static
int
setup_veth_native_bridge_vlan
(
char
*
veth1
,
struct
lxc_netdev
*
netdev
)
{
int
err
,
rc
,
veth1index
;
char
path
[
STRLITERALLEN
(
"/sys/class/net//bridge/vlan_filtering"
)
+
IFNAMSIZ
+
1
];
char
buf
[
5
];
/* Sufficient size to fit max VLAN ID (4094) and null char. */
/* Skip setup if no VLAN options are specified. */
if
(
!
netdev
->
priv
.
veth_attr
.
vlan_id_set
&&
lxc_list_len
(
&
netdev
->
priv
.
veth_attr
.
vlan_tagged_ids
)
<=
0
)
return
0
;
/* Check vlan filtering is enabled on parent bridge. */
rc
=
snprintf
(
path
,
sizeof
(
path
),
"/sys/class/net/%s/bridge/vlan_filtering"
,
netdev
->
link
);
if
(
rc
<
0
||
(
size_t
)
rc
>=
sizeof
(
path
))
return
-
1
;
rc
=
lxc_read_from_file
(
path
,
buf
,
sizeof
(
buf
));
if
(
rc
<
0
)
return
log_error_errno
(
rc
,
errno
,
"Failed reading from
\"
%s
\"
"
,
path
);
buf
[
rc
-
1
]
=
'\0'
;
if
(
strcmp
(
buf
,
"1"
)
!=
0
)
return
log_error_errno
(
-
1
,
EPERM
,
"vlan_filtering is not enabled on
\"
%s
\"
"
,
netdev
->
link
);
/* Get veth1 ifindex for use with netlink. */
veth1index
=
if_nametoindex
(
veth1
);
if
(
!
veth1index
)
return
log_error_errno
(
-
1
,
errno
,
"Failed getting ifindex of
\"
%s
\"
"
,
netdev
->
link
);
/* Configure untagged VLAN settings on bridge port if specified. */
if
(
netdev
->
priv
.
veth_attr
.
vlan_id_set
)
{
unsigned
short
default_pvid
;
/* Get the bridge's default VLAN PVID. */
rc
=
snprintf
(
path
,
sizeof
(
path
),
"/sys/class/net/%s/bridge/default_pvid"
,
netdev
->
link
);
if
(
rc
<
0
||
(
size_t
)
rc
>=
sizeof
(
path
))
return
-
1
;
rc
=
lxc_read_from_file
(
path
,
buf
,
sizeof
(
buf
));
if
(
rc
<
0
)
return
log_error_errno
(
rc
,
errno
,
"Failed reading from
\"
%s
\"
"
,
path
);
buf
[
rc
-
1
]
=
'\0'
;
err
=
get_u16
(
&
default_pvid
,
buf
,
0
);
if
(
err
)
return
log_error_errno
(
-
1
,
EINVAL
,
"Failed parsing default_pvid of
\"
%s
\"
"
,
netdev
->
link
);
/* If the default PVID on the port is not the specified untagged VLAN, then delete it. */
if
(
default_pvid
!=
netdev
->
priv
.
veth_attr
.
vlan_id
)
{
err
=
lxc_bridge_vlan_del
(
veth1index
,
default_pvid
);
if
(
err
)
return
log_error_errno
(
err
,
errno
,
"Failed to delete default untagged vlan
\"
%u
\"
on
\"
%s
\"
"
,
default_pvid
,
veth1
);
}
if
(
netdev
->
priv
.
veth_attr
.
vlan_id
>
BRIDGE_VLAN_NONE
)
{
err
=
lxc_bridge_vlan_add
(
veth1index
,
netdev
->
priv
.
veth_attr
.
vlan_id
,
false
);
if
(
err
)
return
log_error_errno
(
err
,
errno
,
"Failed to add untagged vlan
\"
%u
\"
on
\"
%s
\"
"
,
netdev
->
priv
.
veth_attr
.
vlan_id
,
veth1
);
}
}
/* Configure tagged VLAN settings on bridge port if specified. */
err
=
lxc_bridge_vlan_add_tagged
(
veth1index
,
&
netdev
->
priv
.
veth_attr
.
vlan_tagged_ids
);
if
(
err
)
return
log_error_errno
(
err
,
errno
,
"Failed to add tagged vlans on
\"
%s
\"
"
,
veth1
);
return
0
;
}
struct
ovs_veth_vlan_args
{
const
char
*
nic
;
const
char
*
vlan_mode
;
/* Port VLAN mode. */
short
vlan_id
;
/* PVID VLAN ID. */
const
char
*
trunks
;
/* Comma delimited list of tagged VLAN IDs. */
};
static
int
lxc_ovs_setup_bridge_vlan_exec
(
void
*
data
)
{
struct
ovs_veth_vlan_args
*
args
=
data
;
const
char
*
vlan_mode
=
""
,
*
tag
=
""
,
*
trunks
=
""
;
vlan_mode
=
must_concat
(
NULL
,
"vlan_mode="
,
args
->
vlan_mode
,
(
char
*
)
NULL
);
if
(
args
->
vlan_id
>=
0
)
{
char
buf
[
5
];
int
rc
;
rc
=
snprintf
(
buf
,
sizeof
(
buf
),
"%u"
,
args
->
vlan_id
);
if
(
rc
<
0
||
(
size_t
)
rc
>=
sizeof
(
buf
))
return
log_error_errno
(
-
1
,
EINVAL
,
"Failed to parse ovs bridge vlan
\"
%u
\"
"
,
args
->
vlan_id
);
tag
=
must_concat
(
NULL
,
"tag="
,
buf
,
(
char
*
)
NULL
);
}
if
(
strcmp
(
args
->
trunks
,
""
)
!=
0
)
trunks
=
must_concat
(
NULL
,
"trunks="
,
args
->
trunks
,
(
char
*
)
NULL
);
/* Detect the combination of vlan_id and trunks specified and convert to ovs-vsctl command. */
if
(
strcmp
(
tag
,
""
)
!=
0
&&
strcmp
(
trunks
,
""
)
!=
0
)
execlp
(
"ovs-vsctl"
,
"ovs-vsctl"
,
"set"
,
"port"
,
args
->
nic
,
vlan_mode
,
tag
,
trunks
,
(
char
*
)
NULL
);
else
if
(
strcmp
(
tag
,
""
)
!=
0
)
execlp
(
"ovs-vsctl"
,
"ovs-vsctl"
,
"set"
,
"port"
,
args
->
nic
,
vlan_mode
,
tag
,
(
char
*
)
NULL
);
else
if
(
strcmp
(
trunks
,
""
)
!=
0
)
execlp
(
"ovs-vsctl"
,
"ovs-vsctl"
,
"set"
,
"port"
,
args
->
nic
,
vlan_mode
,
trunks
,
(
char
*
)
NULL
);
else
return
-
EINVAL
;
return
-
errno
;
}
static
int
setup_veth_ovs_bridge_vlan
(
char
*
veth1
,
struct
lxc_netdev
*
netdev
)
{
int
taggedLength
=
lxc_list_len
(
&
netdev
->
priv
.
veth_attr
.
vlan_tagged_ids
);
struct
ovs_veth_vlan_args
args
;
args
.
nic
=
veth1
;
args
.
vlan_mode
=
""
;
args
.
vlan_id
=
-
1
;
args
.
trunks
=
""
;
/* Skip setup if no VLAN options are specified. */
if
(
!
netdev
->
priv
.
veth_attr
.
vlan_id_set
&&
taggedLength
<=
0
)
return
0
;
/* Configure untagged VLAN settings on bridge port if specified. */
if
(
netdev
->
priv
.
veth_attr
.
vlan_id_set
)
{
if
(
netdev
->
priv
.
veth_attr
.
vlan_id
==
BRIDGE_VLAN_NONE
&&
taggedLength
<=
0
)
return
log_error_errno
(
-
1
,
EINVAL
,
"Cannot use vlan.id=none with openvswitch bridges when not using vlan.tagged.id"
);
/* Configure the untagged 'native' membership settings of the port if VLAN ID specified.
* Also set the vlan_mode=access, which will drop any tagged frames.
* Order is important here, as vlan_mode is set to "access", assuming that vlan.tagged.id is not
* used. If vlan.tagged.id is specified, then we expect it to also change the vlan_mode as needed.
*/
if
(
netdev
->
priv
.
veth_attr
.
vlan_id
>
BRIDGE_VLAN_NONE
)
{
args
.
vlan_mode
=
"access"
;
args
.
vlan_id
=
netdev
->
priv
.
veth_attr
.
vlan_id
;
}
}
if
(
taggedLength
>
0
)
{
args
.
vlan_mode
=
"trunk"
;
/* Default to only allowing tagged frames (drop untagged frames). */
if
(
netdev
->
priv
.
veth_attr
.
vlan_id
>
BRIDGE_VLAN_NONE
)
{
/* If untagged vlan mode isn't "none" then allow untagged frames for port's 'native' VLAN. */
args
.
vlan_mode
=
"native-untagged"
;
}
struct
lxc_list
*
iterator
;
lxc_list_for_each
(
iterator
,
&
netdev
->
priv
.
veth_attr
.
vlan_tagged_ids
)
{
unsigned
short
vlan_id
=
PTR_TO_USHORT
(
iterator
->
elem
);
char
buf
[
5
];
/* Sufficient size to fit max VLAN ID (4094) null char. */
int
rc
;
rc
=
snprintf
(
buf
,
sizeof
(
buf
),
"%u"
,
vlan_id
);
if
(
rc
<
0
||
(
size_t
)
rc
>=
sizeof
(
buf
))
return
log_error_errno
(
-
1
,
EINVAL
,
"Failed to parse tagged vlan
\"
%u
\"
for interface
\"
%s
\"
"
,
vlan_id
,
veth1
);
args
.
trunks
=
must_concat
(
NULL
,
args
.
trunks
,
buf
,
","
,
(
char
*
)
NULL
);
}
}
if
(
strcmp
(
args
.
vlan_mode
,
""
)
!=
0
)
{
int
ret
;
char
cmd_output
[
PATH_MAX
];
ret
=
run_command
(
cmd_output
,
sizeof
(
cmd_output
),
lxc_ovs_setup_bridge_vlan_exec
,
(
void
*
)
&
args
);
if
(
ret
<
0
)
return
log_error_errno
(
-
1
,
ret
,
"Failed to setup openvswitch vlan on port
\"
%s
\"
: %s"
,
args
.
nic
,
cmd_output
);
}
return
0
;
}
static
int
instantiate_veth
(
struct
lxc_handler
*
handler
,
struct
lxc_netdev
*
netdev
)
static
int
instantiate_veth
(
struct
lxc_handler
*
handler
,
struct
lxc_netdev
*
netdev
)
{
{
int
err
;
int
err
;
...
@@ -252,6 +535,10 @@ static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netd
...
@@ -252,6 +535,10 @@ static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netd
char
*
veth1
,
*
veth2
;
char
*
veth1
,
*
veth2
;
char
veth1buf
[
IFNAMSIZ
],
veth2buf
[
IFNAMSIZ
];
char
veth1buf
[
IFNAMSIZ
],
veth2buf
[
IFNAMSIZ
];
err
=
validate_veth
(
netdev
);
if
(
err
)
return
err
;
if
(
!
is_empty_string
(
netdev
->
priv
.
veth_attr
.
pair
))
{
if
(
!
is_empty_string
(
netdev
->
priv
.
veth_attr
.
pair
))
{
veth1
=
netdev
->
priv
.
veth_attr
.
pair
;
veth1
=
netdev
->
priv
.
veth_attr
.
pair
;
if
(
handler
->
conf
->
reboot
)
if
(
handler
->
conf
->
reboot
)
...
@@ -324,14 +611,33 @@ static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netd
...
@@ -324,14 +611,33 @@ static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netd
}
}
if
(
!
is_empty_string
(
netdev
->
link
)
&&
netdev
->
priv
.
veth_attr
.
mode
==
VETH_MODE_BRIDGE
)
{
if
(
!
is_empty_string
(
netdev
->
link
)
&&
netdev
->
priv
.
veth_attr
.
mode
==
VETH_MODE_BRIDGE
)
{
if
(
!
lxc_nic_exists
(
netdev
->
link
))
{
SYSERROR
(
"Failed to attach
\"
%s
\"
to bridge
\"
%s
\"
, bridge interface doesn't exist"
,
veth1
,
netdev
->
link
);
goto
out_delete
;
}
err
=
lxc_bridge_attach
(
netdev
->
link
,
veth1
);
err
=
lxc_bridge_attach
(
netdev
->
link
,
veth1
);
if
(
err
)
{
if
(
err
)
{
errno
=
-
err
;
errno
=
-
err
;
SYSERROR
(
"Failed to attach
\"
%s
\"
to bridge
\"
%s
\"
"
,
SYSERROR
(
"Failed to attach
\"
%s
\"
to bridge
\"
%s
\"
"
,
veth1
,
netdev
->
link
);
veth1
,
netdev
->
link
);
goto
out_delete
;
goto
out_delete
;
}
}
INFO
(
"Attached
\"
%s
\"
to bridge
\"
%s
\"
"
,
veth1
,
netdev
->
link
);
INFO
(
"Attached
\"
%s
\"
to bridge
\"
%s
\"
"
,
veth1
,
netdev
->
link
);
if
(
is_ovs_bridge
(
netdev
->
link
))
{
err
=
setup_veth_ovs_bridge_vlan
(
veth1
,
netdev
);
if
(
err
)
{
SYSERROR
(
"Failed to setup openvswitch bridge vlan on
\"
%s
\"
"
,
veth1
);
lxc_ovs_delete_port
(
netdev
->
link
,
veth1
);
goto
out_delete
;
}
}
else
{
err
=
setup_veth_native_bridge_vlan
(
veth1
,
netdev
);
if
(
err
)
{
SYSERROR
(
"Failed to setup native bridge vlan on
\"
%s
\"
"
,
veth1
);
goto
out_delete
;
}
}
}
}
err
=
lxc_netdev_up
(
veth1
);
err
=
lxc_netdev_up
(
veth1
);
...
@@ -555,7 +861,7 @@ static int lxc_ipvlan_create(const char *master, const char *name, int mode, int
...
@@ -555,7 +861,7 @@ static int lxc_ipvlan_create(const char *master, const char *name, int mode, int
err
=
netlink_open
(
nlh_ptr
,
NETLINK_ROUTE
);
err
=
netlink_open
(
nlh_ptr
,
NETLINK_ROUTE
);
if
(
err
)
if
(
err
)
return
ret_errno
(
-
err
)
;
return
err
;
nlmsg
=
nlmsg_alloc
(
NLMSG_GOOD_SIZE
);
nlmsg
=
nlmsg_alloc
(
NLMSG_GOOD_SIZE
);
if
(
!
nlmsg
)
if
(
!
nlmsg
)
...
...
src/lxc/network.h
View file @
677c9967
...
@@ -79,6 +79,9 @@ struct ifla_veth {
...
@@ -79,6 +79,9 @@ struct ifla_veth {
struct
lxc_list
ipv4_routes
;
struct
lxc_list
ipv4_routes
;
struct
lxc_list
ipv6_routes
;
struct
lxc_list
ipv6_routes
;
int
mode
;
/* bridge, router */
int
mode
;
/* bridge, router */
short
vlan_id
;
bool
vlan_id_set
;
struct
lxc_list
vlan_tagged_ids
;
};
};
struct
ifla_vlan
{
struct
ifla_vlan
{
...
...
src/tests/parse_config_file.c
View file @
677c9967
...
@@ -776,6 +776,21 @@ int main(int argc, char *argv[])
...
@@ -776,6 +776,21 @@ int main(int argc, char *argv[])
return
-
1
;
return
-
1
;
}
}
if
(
set_get_compare_clear_save_load_network
(
c
,
"lxc.net.0.veth.vlan.id"
,
"none"
,
tmpf
,
false
,
"veth"
))
{
lxc_error
(
"%s
\n
"
,
"lxc.net.0.veth.vlan.id"
);
return
-
1
;
}
if
(
set_get_compare_clear_save_load_network
(
c
,
"lxc.net.0.veth.vlan.id"
,
"2"
,
tmpf
,
true
,
"veth"
))
{
lxc_error
(
"%s
\n
"
,
"lxc.net.0.veth.vlan.id"
);
return
-
1
;
}
if
(
set_get_compare_clear_save_load_network
(
c
,
"lxc.net.0.veth.vlan.tagged.id"
,
"2"
,
tmpf
,
true
,
"veth"
))
{
lxc_error
(
"%s
\n
"
,
"lxc.net.0.veth.vlan.tagged.id"
);
return
-
1
;
}
if
(
set_get_compare_clear_save_load
(
c
,
"lxc.net.0.script.up"
,
"/some/up/path"
,
tmpf
,
true
))
{
if
(
set_get_compare_clear_save_load
(
c
,
"lxc.net.0.script.up"
,
"/some/up/path"
,
tmpf
,
true
))
{
lxc_error
(
"%s
\n
"
,
"lxc.net.0.script.up"
);
lxc_error
(
"%s
\n
"
,
"lxc.net.0.script.up"
);
goto
non_test_error
;
goto
non_test_error
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment