Skip to content

Commit 8c57ff2

Browse files
committed
nanny: add device references to policy match (bsc#941611)
Generate a match to all devices a config refers in it's link node (master device, ovs-bridge, ...) to ensure, that there is already the complete configuration tree applied to nanny in order to not start managing a port/slave and fail on unresolvable requirements.
1 parent bf11901 commit 8c57ff2

File tree

4 files changed

+237
-7
lines changed

4 files changed

+237
-7
lines changed

client/ifup.c

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,93 @@ __ni_ifup_generate_match_dev(xml_node_t *node, ni_ifworker_t *w)
7373
return xml_node_new_element(NI_NANNY_IFPOLICY_MATCH_DEV, node, w->name);
7474
}
7575

76+
static ni_bool_t
77+
__ni_ifup_generate_match_link_port_ref(xml_node_t *match, xml_node_t *port)
78+
{
79+
const char *type = xml_node_get_attr(port, NI_CLIENT_IFCONFIG_PORT_TYPE);
80+
ni_iftype_t ptype = ni_linktype_name_to_type(type);
81+
xml_node_t *ref, *ovsbr;
82+
83+
switch (ptype) {
84+
case NI_IFTYPE_OVS_BRIDGE:
85+
ovsbr = xml_node_get_child(port, NI_CLIENT_IFCONFIG_BRIDGE);
86+
if (!ovsbr || ni_string_empty(ovsbr->cdata))
87+
return FALSE;
88+
89+
if (!(ref = xml_node_new(NI_NANNY_IFPOLICY_MATCH_REF, match)))
90+
return FALSE;
91+
92+
if (!xml_node_new_element(NI_NANNY_IFPOLICY_MATCH_DEV, ref, ovsbr->cdata)) {
93+
xml_node_free(ref);
94+
return FALSE;
95+
}
96+
break;
97+
98+
default:
99+
/* other port types need master only */
100+
break;
101+
}
102+
return TRUE;
103+
}
104+
105+
static ni_bool_t
106+
__ni_ifup_generate_match_link_ref(xml_node_t *match, xml_node_t *link)
107+
{
108+
xml_node_t *ref, *master, *port;
109+
110+
if (!(master = xml_node_get_child(link, NI_CLIENT_IFCONFIG_MASTER)))
111+
return TRUE; /* <link> does not contain a <master> node */
112+
113+
if (ni_string_empty(master->cdata))
114+
return FALSE;
115+
116+
if (!(ref = xml_node_new(NI_NANNY_IFPOLICY_MATCH_REF, match)))
117+
return FALSE;
118+
119+
if (!xml_node_new_element(NI_NANNY_IFPOLICY_MATCH_DEV, ref, master->cdata)) {
120+
xml_node_free(ref);
121+
return FALSE;
122+
}
123+
124+
if ((port = xml_node_get_child(link, NI_CLIENT_IFCONFIG_LINK_PORT)))
125+
return __ni_ifup_generate_match_link_port_ref(match, port);
126+
127+
return TRUE; /* master ref at least */
128+
}
129+
130+
static ni_bool_t
131+
__ni_ifup_generate_match_master_ref(xml_node_t *match, ni_ifworker_t *master)
132+
{
133+
xml_node_t *ref;
134+
135+
if (!master || ni_string_empty(master->name))
136+
return FALSE;
137+
138+
if (!(ref = xml_node_new(NI_NANNY_IFPOLICY_MATCH_REF, match)))
139+
return FALSE;
140+
141+
if (!xml_node_new_element(NI_NANNY_IFPOLICY_MATCH_DEV, ref, master->name)) {
142+
xml_node_free(ref);
143+
return FALSE;
144+
}
145+
146+
return TRUE;
147+
}
148+
149+
static ni_bool_t
150+
__ni_ifup_generate_match_refs(xml_node_t *match, ni_ifworker_t *w)
151+
{
152+
xml_node_t *link;
153+
154+
if (w->masterdev)
155+
return __ni_ifup_generate_match_master_ref(match, w->masterdev);
156+
157+
if ((link = xml_node_get_child(w->config.node, NI_CLIENT_IFCONFIG_LINK)))
158+
return __ni_ifup_generate_match_link_ref(match, link);
159+
160+
return TRUE; /* no refs is not an error */
161+
}
162+
76163
static xml_node_t *
77164
__ni_ifup_generate_match(const char *name, ni_ifworker_t *w)
78165
{
@@ -81,18 +168,34 @@ __ni_ifup_generate_match(const char *name, ni_ifworker_t *w)
81168
if (!(match = xml_node_new(name, NULL)))
82169
goto error;
83170

171+
ni_debug_wicked_xml(w->config.node, NI_LOG_DEBUG,
172+
"generate policy match for %s (type %s)", w->name,
173+
ni_linktype_type_to_name(w->iftype));
174+
84175
if (!__ni_ifup_generate_match_dev(match, w))
85176
goto error;
86177

87-
/* Ignore child dependency for following device types */
178+
/* Ignore child dependency for following device types:
179+
* - ovs-system: otherwise ovs-system would require all ports
180+
* in all ovs-bridges and want to get at least one up ...
181+
* this is not what we want :-)
182+
*/
88183
switch (w->iftype) {
89184
case NI_IFTYPE_OVS_SYSTEM:
90185
goto done;
91186
break;
92187
default:
188+
if (ni_string_eq(w->name, ni_linktype_type_to_name(NI_IFTYPE_OVS_SYSTEM)))
189+
goto done;
93190
break;
94191
}
95192

193+
if (!__ni_ifup_generate_match_refs(match, w)) {
194+
ni_debug_application("%s: unable to generate policy match device references",
195+
w->name);
196+
goto error;
197+
}
198+
96199
if (w->children.count) {
97200
xml_node_t *or;
98201
unsigned int i;

src/client/ifconfig.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@
3131
#define NI_CLIENT_IFCONFIG_MODE "mode"
3232
#define NI_CLIENT_IFCONFIG_LINK "link"
3333
#define NI_CLIENT_IFCONFIG_MASTER "master"
34+
#define NI_CLIENT_IFCONFIG_LINK_PORT "port"
35+
#define NI_CLIENT_IFCONFIG_PORT_TYPE "type"
36+
#define NI_CLIENT_IFCONFIG_BRIDGE "bridge"
3437
#define NI_CLIENT_IFCONFIG_IPV4 "ipv4"
3538
#define NI_CLIENT_IFCONFIG_IPV6 "ipv6"
3639
#define NI_CLIENT_IFCONFIG_IP_ENABLED "enabled"
@@ -45,6 +48,7 @@
4548
#define NI_NANNY_IFPOLICY_MATCH_COND_CHILD "child"
4649
#define NI_NANNY_IFPOLICY_MATCH_ALWAYS_TRUE "any"
4750
#define NI_NANNY_IFPOLICY_MATCH_DEV "device"
51+
#define NI_NANNY_IFPOLICY_MATCH_REF "reference"
4852
#define NI_NANNY_IFPOLICY_MATCH_MIN_STATE "minimum-device-state"
4953
#define NI_NANNY_IFPOLICY_MATCH_LINK_TYPE "link-type"
5054
#define NI_NANNY_IFPOLICY_MERGE "merge"

src/fsm-policy.c

Lines changed: 127 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,10 @@ struct ni_ifcondition {
2828
ni_ifcondition_free_fn_t * free;
2929

3030
union {
31-
ni_ifworker_type_t type;
31+
struct {
32+
ni_ifworker_type_t type;
33+
ni_ifcondition_t * ref;
34+
};
3235
struct {
3336
ni_ifcondition_t *left;
3437
ni_ifcondition_t *right;
@@ -1037,6 +1040,11 @@ ni_ifcondition_free_args_string(ni_ifcondition_t *cond)
10371040
{
10381041
ni_string_free(&cond->args.string);
10391042
}
1043+
static void
1044+
ni_ifcondition_free_args_reference(ni_ifcondition_t *cond)
1045+
{
1046+
ni_ifcondition_free(cond->args.ref);
1047+
}
10401048

10411049
static ni_ifcondition_t *
10421050
ni_ifcondition_new_cdata(ni_ifcondition_check_fn_t *check_fn, const xml_node_t *node)
@@ -1608,6 +1616,120 @@ ni_ifcondition_modem(xml_node_t *node)
16081616
return result;
16091617
}
16101618

1619+
static ni_bool_t
1620+
__ni_fsm_policy_match_reference(const ni_ifcondition_t *cond, const ni_fsm_t *fsm, ni_ifworker_t *w)
1621+
{
1622+
unsigned int i;
1623+
1624+
if (cond && cond->args.ref && fsm) {
1625+
for (i = 0; i < fsm->workers.count; ++i) {
1626+
w = fsm->workers.data[i];
1627+
if (!w || w->type != cond->args.type)
1628+
continue;
1629+
1630+
if (ni_ifcondition_check(cond->args.ref, fsm, w))
1631+
return TRUE;
1632+
}
1633+
}
1634+
return FALSE;
1635+
}
1636+
1637+
static ni_ifcondition_t *
1638+
ni_ifcondition_new_reference(ni_ifcondition_t *ref, ni_ifworker_type_t type)
1639+
{
1640+
ni_ifcondition_t *cond;
1641+
1642+
if (ref) {
1643+
cond = ni_ifcondition_new(__ni_fsm_policy_match_reference);
1644+
cond->free = ni_ifcondition_free_args_reference;
1645+
cond->args.ref = ref;
1646+
cond->args.type = type;
1647+
return cond;
1648+
}
1649+
return NULL;
1650+
}
1651+
1652+
static inline ni_bool_t
1653+
ni_ifcondition_reference_bind_type(ni_ifworker_type_t *bound, ni_ifworker_type_t type)
1654+
{
1655+
if (*bound == NI_IFWORKER_TYPE_NONE) {
1656+
*bound = type;
1657+
return TRUE;
1658+
} else {
1659+
return *bound == type;
1660+
}
1661+
}
1662+
1663+
static ni_ifcondition_t *
1664+
ni_ifcondition_reference_type_element(ni_ifworker_type_t *type, xml_node_t *node, const char *name)
1665+
{
1666+
if (ni_string_eq(name, "device")) {
1667+
if (ni_ifcondition_reference_bind_type(type, NI_IFWORKER_TYPE_NETDEV))
1668+
return ni_ifcondition_device(node);
1669+
1670+
ni_error("%s: invalid <%s> reference element type mix", name, xml_node_location(node));
1671+
return NULL;
1672+
}
1673+
if (ni_string_eq(name, "modem")) {
1674+
if (ni_ifcondition_reference_bind_type(type, NI_IFWORKER_TYPE_MODEM))
1675+
return ni_ifcondition_modem(node);
1676+
1677+
ni_error("%s: invalid <%s> reference element type mix", name, xml_node_location(node));
1678+
return NULL;
1679+
}
1680+
1681+
ni_error("%s: unknown reference condition <%s>", xml_node_location(node), name);
1682+
return NULL;
1683+
}
1684+
1685+
/*
1686+
* <reference:device>...</reference:device>
1687+
* <reference:modem>...</reference:modem>
1688+
*
1689+
* Match a single property element of a referenced worker.
1690+
*/
1691+
static ni_ifcondition_t *
1692+
ni_ifcondition_reference_element(xml_node_t *node, const char *name)
1693+
{
1694+
ni_ifworker_type_t type = NI_IFWORKER_TYPE_NONE;
1695+
ni_ifcondition_t *cond;
1696+
1697+
cond = ni_ifcondition_reference_type_element(&type, node, name);
1698+
return ni_ifcondition_new_reference(cond, type);
1699+
}
1700+
1701+
/*
1702+
* <reference>...and device property match...</reference>
1703+
* <reference>...and modem property match...</reference>
1704+
*
1705+
* Each worker has a type (modem or device) and a reference is bond to
1706+
* the type of the 1st worker matching it's properties using an and term.
1707+
*/
1708+
static ni_ifcondition_t *
1709+
ni_ifcondition_reference(xml_node_t *node)
1710+
{
1711+
ni_ifcondition_t *result = NULL;
1712+
ni_ifworker_type_t type = NI_IFWORKER_TYPE_NONE;
1713+
1714+
for (node = node->children; node; node = node->next) {
1715+
ni_ifcondition_t *cond;
1716+
1717+
cond = ni_ifcondition_reference_type_element(&type, node, node->name);
1718+
if (cond == NULL) {
1719+
if (result)
1720+
ni_ifcondition_free(result);
1721+
return NULL;
1722+
}
1723+
1724+
if (result == NULL)
1725+
result = cond;
1726+
else
1727+
result = ni_ifcondition_and_terms(result, cond);
1728+
}
1729+
1730+
return ni_ifcondition_new_reference(result, type);
1731+
}
1732+
16111733
/*
16121734
* <wireless>...</wireless>
16131735
* <wireless:foobar>...</wireless:foobar>
@@ -1751,6 +1873,10 @@ ni_ifcondition_from_xml(xml_node_t *node)
17511873
return ni_ifcondition_device(node);
17521874
if (!strncmp(node->name, "device:", sizeof("device:")-1))
17531875
return ni_ifcondition_device_element(node, node->name + sizeof("device:")-1);
1876+
if (!strcmp(node->name, "reference"))
1877+
return ni_ifcondition_reference(node);
1878+
if (!strncmp(node->name, "reference:", sizeof("reference:")-1))
1879+
return ni_ifcondition_reference_element(node, node->name + sizeof("reference:")-1);
17541880
if (!strcmp(node->name, "child"))
17551881
return ni_ifcondition_and_child(node);
17561882
if (!strcmp(node->name, "modem"))

src/fsm.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -959,14 +959,11 @@ ni_ifworker_match_netdev_name(const ni_ifworker_t *w, const char *ifname)
959959
if (!w || ni_string_empty(ifname))
960960
return FALSE;
961961

962-
/* ifworker name must be same as policy name here.
963-
* If device name matches policy name then we
964-
* consider such a match as fulfilled.
965-
*/
966962
if (ni_string_eq(w->name, ifname))
967963
return TRUE;
968964

969-
ni_error("device %s requested via match is not present", ifname);
965+
ni_debug_verbose(NI_LOG_DEBUG1, NI_TRACE_APPLICATION,
966+
"device %s requested via match is not present", ifname);
970967
return FALSE;
971968
}
972969

0 commit comments

Comments
 (0)